diff --git a/cts/patterns.py b/cts/patterns.py index e734f40..13307e5 100644 --- a/cts/patterns.py +++ b/cts/patterns.py @@ -180,6 +180,9 @@ class crm_cs_v0(BasePatterns): r"error: log_operation:.*Operation 'reboot' .* with device 'FencingFail' returned:", r"Child process .* terminated with signal 9", r"getinfo response error: 1$", + "sbd.* error: inquisitor_child: DEBUG MODE IS ACTIVE", + "sbd.* pcmk: error: crm_ipc_read: Connection to cib_ro failed", + "sbd.* pcmk: error: mainloop_gio_callback: Connection to cib_ro.* closed .I/O condition=17", ] self.BadNews = [ diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c index 7423af1..baf6cb9 100644 --- a/lib/pengine/utils.c +++ b/lib/pengine/utils.c @@ -74,6 +74,7 @@ node_copy(node_t * this_node) crm_trace("Copying %p (%s) to %p", this_node, this_node->details->uname, new_node); + new_node->rsc_discover_mode = this_node->rsc_discover_mode; new_node->weight = this_node->weight; new_node->fixed = this_node->fixed; new_node->details = this_node->details; diff --git a/lib/services/systemd.c b/lib/services/systemd.c index 51ade44..a8bf1b4 100644 --- a/lib/services/systemd.c +++ b/lib/services/systemd.c @@ -461,10 +461,10 @@ systemd_async_dispatch(DBusPendingCall *pending, void *user_data) if(op) { crm_trace("Got result: %p for %p for %s, %s", reply, pending, op->rsc, op->action); + op->opaque->pending = NULL; } else { crm_trace("Got result: %p for %p", reply, pending); } - op->opaque->pending = NULL; systemd_exec_result(reply, op); if(pending) { diff --git a/pengine/allocate.c b/pengine/allocate.c index e708e26..45e2212 100644 --- a/pengine/allocate.c +++ b/pengine/allocate.c @@ -948,6 +948,28 @@ probe_resources(pe_working_set_t * data_set) return TRUE; } +static void +rsc_discover_filter(resource_t *rsc, node_t *node) +{ + GListPtr gIter = rsc->children; + resource_t *top = uber_parent(rsc); + node_t *match; + + if (rsc->exclusive_discover == FALSE && top->exclusive_discover == FALSE) { + return; + } + + for (; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t *) gIter->data; + rsc_discover_filter(child_rsc, node); + } + + match = g_hash_table_lookup(rsc->allowed_nodes, node->details->id); + if (match && match->rsc_discover_mode != discover_exclusive) { + match->weight = -INFINITY; + } +} + /* * Count how many valid nodes we have (so we know the maximum number of * colors we can resolve). @@ -986,6 +1008,7 @@ stage2(pe_working_set_t * data_set) resource_t *rsc = (resource_t *) gIter2->data; common_apply_stickiness(rsc, node, data_set); + rsc_discover_filter(rsc, node); } } diff --git a/pengine/native.c b/pengine/native.c index 3dca702..6d62010 100644 --- a/pengine/native.c +++ b/pengine/native.c @@ -2103,6 +2103,9 @@ native_rsc_location(resource_t * rsc, rsc_to_node_t * constraint) } if (other_node->rsc_discover_mode < constraint->discover_mode) { + if (constraint->discover_mode == discover_exclusive) { + rsc->exclusive_discover = TRUE; + } /* exclusive > never > always... always is default */ other_node->rsc_discover_mode = constraint->discover_mode; } diff --git a/pengine/test10/resource-discovery.dot b/pengine/test10/resource-discovery.dot index efb2434..5b1aab9 100644 --- a/pengine/test10/resource-discovery.dot +++ b/pengine/test10/resource-discovery.dot @@ -1,41 +1,26 @@ digraph "g" { -"FAKE1_monitor_0 18builder" -> "probe_complete 18builder" [ style = bold] -"FAKE1_monitor_0 18builder" [ style=bold color="green" fontcolor="black"] -"FAKE1_monitor_0 18node1" -> "probe_complete 18node1" [ style = bold] -"FAKE1_monitor_0 18node1" [ style=bold color="green" fontcolor="black"] -"FAKE1_monitor_0 18node2" -> "probe_complete 18node2" [ style = bold] -"FAKE1_monitor_0 18node2" [ style=bold color="green" fontcolor="black"] -"FAKE1_monitor_0 18node3" -> "probe_complete 18node3" [ style = bold] -"FAKE1_monitor_0 18node3" [ style=bold color="green" fontcolor="black"] "FAKE1_monitor_0 18node4" -> "probe_complete 18node4" [ style = bold] "FAKE1_monitor_0 18node4" [ style=bold color="green" fontcolor="black"] -"FAKE1_monitor_60000 18node2" [ style=bold color="green" fontcolor="black"] -"FAKE1_start_0 18node2" -> "FAKE1_monitor_60000 18node2" [ style = bold] -"FAKE1_start_0 18node2" [ style=bold color="green" fontcolor="black"] -"FAKE2_monitor_60000 18node3" [ style=bold color="green" fontcolor="black"] -"FAKE2_start_0 18node3" -> "FAKE2_monitor_60000 18node3" [ style = bold] -"FAKE2_start_0 18node3" [ style=bold color="green" fontcolor="black"] -"FAKE2_stop_0 18node2" -> "FAKE2_start_0 18node3" [ style = bold] -"FAKE2_stop_0 18node2" -> "all_stopped" [ style = bold] -"FAKE2_stop_0 18node2" [ style=bold color="green" fontcolor="black"] +"FAKE1_monitor_60000 18node4" [ style=bold color="green" fontcolor="black"] +"FAKE1_start_0 18node4" -> "FAKE1_monitor_60000 18node4" [ style = bold] +"FAKE1_start_0 18node4" [ style=bold color="green" fontcolor="black"] +"FAKE2_monitor_0 18node1" -> "probe_complete 18node1" [ style = bold] +"FAKE2_monitor_0 18node1" [ style=bold color="green" fontcolor="black"] +"FAKE2_monitor_0 18node2" -> "probe_complete 18node2" [ style = bold] +"FAKE2_monitor_0 18node2" [ style=bold color="green" fontcolor="black"] +"FAKE2_monitor_60000 18node2" [ style=bold color="green" fontcolor="black"] +"FAKE2_start_0 18node2" -> "FAKE2_monitor_60000 18node2" [ style = bold] +"FAKE2_start_0 18node2" [ style=bold color="green" fontcolor="black"] "FAKE3_monitor_0 18node3" -> "probe_complete 18node3" [ style = bold] "FAKE3_monitor_0 18node3" [ style=bold color="green" fontcolor="black"] "FAKE3_monitor_60000 18node3" [ style=bold color="green" fontcolor="black"] "FAKE3_start_0 18node3" -> "FAKE3_monitor_60000 18node3" [ style = bold] "FAKE3_start_0 18node3" [ style=bold color="green" fontcolor="black"] -"FAKE3_stop_0 18builder" -> "FAKE3_start_0 18node3" [ style = bold] -"FAKE3_stop_0 18builder" -> "all_stopped" [ style = bold] -"FAKE3_stop_0 18builder" [ style=bold color="green" fontcolor="black"] "FAKE4_monitor_0 18node4" -> "probe_complete 18node4" [ style = bold] "FAKE4_monitor_0 18node4" [ style=bold color="green" fontcolor="black"] "FAKE4_monitor_60000 18node4" [ style=bold color="green" fontcolor="black"] "FAKE4_start_0 18node4" -> "FAKE4_monitor_60000 18node4" [ style = bold] "FAKE4_start_0 18node4" [ style=bold color="green" fontcolor="black"] -"FAKE4_stop_0 18node1" -> "FAKE4_start_0 18node4" [ style = bold] -"FAKE4_stop_0 18node1" -> "all_stopped" [ style = bold] -"FAKE4_stop_0 18node1" [ style=bold color="green" fontcolor="black"] -"FAKE5_monitor_0 18builder" -> "probe_complete 18builder" [ style = bold] -"FAKE5_monitor_0 18builder" [ style=bold color="green" fontcolor="black"] "FAKE5_monitor_0 18node1" -> "probe_complete 18node1" [ style = bold] "FAKE5_monitor_0 18node1" [ style=bold color="green" fontcolor="black"] "FAKE5_monitor_0 18node2" -> "probe_complete 18node2" [ style = bold] @@ -49,56 +34,54 @@ "FAKE5_monitor_60000 remote1" [ style=bold color="green" fontcolor="black"] "FAKE5_start_0 remote1" -> "FAKE5_monitor_60000 remote1" [ style = bold] "FAKE5_start_0 remote1" [ style=bold color="green" fontcolor="black"] +"FAKE6_monitor_0 18node1" -> "probe_complete 18node1" [ style = bold] +"FAKE6_monitor_0 18node1" [ style=bold color="green" fontcolor="black"] +"FAKE6_monitor_0 18node2" -> "probe_complete 18node2" [ style = bold] +"FAKE6_monitor_0 18node2" [ style=bold color="green" fontcolor="black"] +"FAKE6_monitor_10000 18node1" [ style=bold color="green" fontcolor="black"] +"FAKE6_start_0 18node1" -> "FAKE6_monitor_10000 18node1" [ style = bold] +"FAKE6_start_0 18node1" -> "FAKE7_start_0 18node1" [ style = bold] +"FAKE6_start_0 18node1" -> "FAKEGROUP_running_0" [ style = bold] +"FAKE6_start_0 18node1" [ style=bold color="green" fontcolor="black"] +"FAKE7_monitor_0 18node1" -> "probe_complete 18node1" [ style = bold] +"FAKE7_monitor_0 18node1" [ style=bold color="green" fontcolor="black"] +"FAKE7_monitor_0 18node2" -> "probe_complete 18node2" [ style = bold] +"FAKE7_monitor_0 18node2" [ style=bold color="green" fontcolor="black"] +"FAKE7_monitor_10000 18node1" [ style=bold color="green" fontcolor="black"] +"FAKE7_start_0 18node1" -> "FAKE7_monitor_10000 18node1" [ style = bold] +"FAKE7_start_0 18node1" -> "FAKEGROUP_running_0" [ style = bold] +"FAKE7_start_0 18node1" [ style=bold color="green" fontcolor="black"] "FAKECLONE1-clone_running_0" [ style=bold color="green" fontcolor="orange"] "FAKECLONE1-clone_start_0" -> "FAKECLONE1-clone_running_0" [ style = bold] -"FAKECLONE1-clone_start_0" -> "FAKECLONE1:0_start_0 18builder" [ style = bold] -"FAKECLONE1-clone_start_0" -> "FAKECLONE1:1_start_0 18node1" [ style = bold] -"FAKECLONE1-clone_start_0" -> "FAKECLONE1:2_start_0 18node2" [ style = bold] -"FAKECLONE1-clone_start_0" -> "FAKECLONE1:3_start_0 18node4" [ style = bold] -"FAKECLONE1-clone_start_0" -> "FAKECLONE1:4_start_0 remote1" [ style = bold] -"FAKECLONE1-clone_start_0" -> "FAKECLONE1:5_start_0 18node3" [ style = bold] +"FAKECLONE1-clone_start_0" -> "FAKECLONE1:0_start_0 18node1" [ style = bold] +"FAKECLONE1-clone_start_0" -> "FAKECLONE1:1_start_0 remote1" [ style = bold] "FAKECLONE1-clone_start_0" [ style=bold color="green" fontcolor="orange"] -"FAKECLONE1:0_monitor_60000 18builder" [ style=bold color="green" fontcolor="black"] -"FAKECLONE1:0_start_0 18builder" -> "FAKECLONE1-clone_running_0" [ style = bold] -"FAKECLONE1:0_start_0 18builder" -> "FAKECLONE1:0_monitor_60000 18builder" [ style = bold] -"FAKECLONE1:0_start_0 18builder" [ style=bold color="green" fontcolor="black"] -"FAKECLONE1:1_monitor_60000 18node1" [ style=bold color="green" fontcolor="black"] -"FAKECLONE1:1_start_0 18node1" -> "FAKECLONE1-clone_running_0" [ style = bold] -"FAKECLONE1:1_start_0 18node1" -> "FAKECLONE1:1_monitor_60000 18node1" [ style = bold] -"FAKECLONE1:1_start_0 18node1" [ style=bold color="green" fontcolor="black"] -"FAKECLONE1:2_monitor_60000 18node2" [ style=bold color="green" fontcolor="black"] -"FAKECLONE1:2_start_0 18node2" -> "FAKECLONE1-clone_running_0" [ style = bold] -"FAKECLONE1:2_start_0 18node2" -> "FAKECLONE1:2_monitor_60000 18node2" [ style = bold] -"FAKECLONE1:2_start_0 18node2" [ style=bold color="green" fontcolor="black"] -"FAKECLONE1:3_monitor_60000 18node4" [ style=bold color="green" fontcolor="black"] -"FAKECLONE1:3_start_0 18node4" -> "FAKECLONE1-clone_running_0" [ style = bold] -"FAKECLONE1:3_start_0 18node4" -> "FAKECLONE1:3_monitor_60000 18node4" [ style = bold] -"FAKECLONE1:3_start_0 18node4" [ style=bold color="green" fontcolor="black"] -"FAKECLONE1:4_monitor_0 remote1" -> "probe_complete remote1" [ style = bold] -"FAKECLONE1:4_monitor_0 remote1" [ style=bold color="green" fontcolor="black"] -"FAKECLONE1:4_monitor_60000 remote1" [ style=bold color="green" fontcolor="black"] -"FAKECLONE1:4_start_0 remote1" -> "FAKECLONE1-clone_running_0" [ style = bold] -"FAKECLONE1:4_start_0 remote1" -> "FAKECLONE1:4_monitor_60000 remote1" [ style = bold] -"FAKECLONE1:4_start_0 remote1" [ style=bold color="green" fontcolor="black"] -"FAKECLONE1:5_monitor_60000 18node3" [ style=bold color="green" fontcolor="black"] -"FAKECLONE1:5_start_0 18node3" -> "FAKECLONE1-clone_running_0" [ style = bold] -"FAKECLONE1:5_start_0 18node3" -> "FAKECLONE1:5_monitor_60000 18node3" [ style = bold] -"FAKECLONE1:5_start_0 18node3" [ style=bold color="green" fontcolor="black"] +"FAKECLONE1:0_monitor_0 18node1" -> "probe_complete 18node1" [ style = bold] +"FAKECLONE1:0_monitor_0 18node1" [ style=bold color="green" fontcolor="black"] +"FAKECLONE1:0_monitor_60000 18node1" [ style=bold color="green" fontcolor="black"] +"FAKECLONE1:0_start_0 18node1" -> "FAKECLONE1-clone_running_0" [ style = bold] +"FAKECLONE1:0_start_0 18node1" -> "FAKECLONE1:0_monitor_60000 18node1" [ style = bold] +"FAKECLONE1:0_start_0 18node1" [ style=bold color="green" fontcolor="black"] +"FAKECLONE1:1_monitor_0 remote1" -> "probe_complete remote1" [ style = bold] +"FAKECLONE1:1_monitor_0 remote1" [ style=bold color="green" fontcolor="black"] +"FAKECLONE1:1_monitor_60000 remote1" [ style=bold color="green" fontcolor="black"] +"FAKECLONE1:1_start_0 remote1" -> "FAKECLONE1-clone_running_0" [ style = bold] +"FAKECLONE1:1_start_0 remote1" -> "FAKECLONE1:1_monitor_60000 remote1" [ style = bold] +"FAKECLONE1:1_start_0 remote1" [ style=bold color="green" fontcolor="black"] "FAKECLONE2-clone_running_0" [ style=bold color="green" fontcolor="orange"] "FAKECLONE2-clone_start_0" -> "FAKECLONE2-clone_running_0" [ style = bold] -"FAKECLONE2-clone_start_0" -> "FAKECLONE2:0_start_0 18builder" [ style = bold] +"FAKECLONE2-clone_start_0" -> "FAKECLONE2:0_start_0 18node3" [ style = bold] "FAKECLONE2-clone_start_0" -> "FAKECLONE2:1_start_0 18node1" [ style = bold] "FAKECLONE2-clone_start_0" -> "FAKECLONE2:2_start_0 18node2" [ style = bold] "FAKECLONE2-clone_start_0" -> "FAKECLONE2:3_start_0 18node4" [ style = bold] "FAKECLONE2-clone_start_0" -> "FAKECLONE2:4_start_0 remote1" [ style = bold] -"FAKECLONE2-clone_start_0" -> "FAKECLONE2:5_start_0 18node3" [ style = bold] "FAKECLONE2-clone_start_0" [ style=bold color="green" fontcolor="orange"] -"FAKECLONE2:0_monitor_0 18builder" -> "probe_complete 18builder" [ style = bold] -"FAKECLONE2:0_monitor_0 18builder" [ style=bold color="green" fontcolor="black"] -"FAKECLONE2:0_monitor_60000 18builder" [ style=bold color="green" fontcolor="black"] -"FAKECLONE2:0_start_0 18builder" -> "FAKECLONE2-clone_running_0" [ style = bold] -"FAKECLONE2:0_start_0 18builder" -> "FAKECLONE2:0_monitor_60000 18builder" [ style = bold] -"FAKECLONE2:0_start_0 18builder" [ style=bold color="green" fontcolor="black"] +"FAKECLONE2:0_monitor_0 18node3" -> "probe_complete 18node3" [ style = bold] +"FAKECLONE2:0_monitor_0 18node3" [ style=bold color="green" fontcolor="black"] +"FAKECLONE2:0_monitor_60000 18node3" [ style=bold color="green" fontcolor="black"] +"FAKECLONE2:0_start_0 18node3" -> "FAKECLONE2-clone_running_0" [ style = bold] +"FAKECLONE2:0_start_0 18node3" -> "FAKECLONE2:0_monitor_60000 18node3" [ style = bold] +"FAKECLONE2:0_start_0 18node3" [ style=bold color="green" fontcolor="black"] "FAKECLONE2:1_monitor_0 18node1" -> "probe_complete 18node1" [ style = bold] "FAKECLONE2:1_monitor_0 18node1" [ style=bold color="green" fontcolor="black"] "FAKECLONE2:1_monitor_60000 18node1" [ style=bold color="green" fontcolor="black"] @@ -121,15 +104,11 @@ "FAKECLONE2:4_start_0 remote1" -> "FAKECLONE2-clone_running_0" [ style = bold] "FAKECLONE2:4_start_0 remote1" -> "FAKECLONE2:4_monitor_60000 remote1" [ style = bold] "FAKECLONE2:4_start_0 remote1" [ style=bold color="green" fontcolor="black"] -"FAKECLONE2:5_monitor_0 18node3" -> "probe_complete 18node3" [ style = bold] -"FAKECLONE2:5_monitor_0 18node3" [ style=bold color="green" fontcolor="black"] -"FAKECLONE2:5_monitor_60000 18node3" [ style=bold color="green" fontcolor="black"] -"FAKECLONE2:5_start_0 18node3" -> "FAKECLONE2-clone_running_0" [ style = bold] -"FAKECLONE2:5_start_0 18node3" -> "FAKECLONE2:5_monitor_60000 18node3" [ style = bold] -"FAKECLONE2:5_start_0 18node3" [ style=bold color="green" fontcolor="black"] -"all_stopped" [ style=bold color="green" fontcolor="orange"] -"probe_complete 18builder" -> "probe_nodes_complete" [ style = bold] -"probe_complete 18builder" [ style=bold color="green" fontcolor="black"] +"FAKEGROUP_running_0" [ style=bold color="green" fontcolor="orange"] +"FAKEGROUP_start_0" -> "FAKE6_start_0 18node1" [ style = bold] +"FAKEGROUP_start_0" -> "FAKE7_start_0 18node1" [ style = bold] +"FAKEGROUP_start_0" -> "FAKEGROUP_running_0" [ style = bold] +"FAKEGROUP_start_0" [ style=bold color="green" fontcolor="orange"] "probe_complete 18node1" -> "probe_nodes_complete" [ style = bold] "probe_complete 18node1" [ style=bold color="green" fontcolor="black"] "probe_complete 18node2" -> "probe_nodes_complete" [ style = bold] @@ -140,46 +119,53 @@ "probe_complete 18node4" [ style=bold color="green" fontcolor="black"] "probe_complete remote1" -> "probe_complete" [ style = bold] "probe_complete remote1" [ style=bold color="green" fontcolor="black"] -"probe_complete" -> "FAKE1_start_0 18node2" [ style = bold] -"probe_complete" -> "FAKE2_stop_0 18node2" [ style = bold] +"probe_complete" -> "FAKE1_start_0 18node4" [ style = bold] +"probe_complete" -> "FAKE2_start_0 18node2" [ style = bold] "probe_complete" -> "FAKE3_start_0 18node3" [ style = bold] -"probe_complete" -> "FAKE3_stop_0 18builder" [ style = bold] "probe_complete" -> "FAKE4_start_0 18node4" [ style = bold] -"probe_complete" -> "FAKE4_stop_0 18node1" [ style = bold] "probe_complete" -> "FAKE5_start_0 remote1" [ style = bold] -"probe_complete" -> "FAKECLONE1:0_start_0 18builder" [ style = bold] -"probe_complete" -> "FAKECLONE1:1_start_0 18node1" [ style = bold] -"probe_complete" -> "FAKECLONE1:2_start_0 18node2" [ style = bold] -"probe_complete" -> "FAKECLONE1:3_start_0 18node4" [ style = bold] -"probe_complete" -> "FAKECLONE1:4_start_0 remote1" [ style = bold] -"probe_complete" -> "FAKECLONE1:5_start_0 18node3" [ style = bold] -"probe_complete" -> "FAKECLONE2:0_start_0 18builder" [ style = bold] +"probe_complete" -> "FAKE6_start_0 18node1" [ style = bold] +"probe_complete" -> "FAKE7_start_0 18node1" [ style = bold] +"probe_complete" -> "FAKECLONE1:0_start_0 18node1" [ style = bold] +"probe_complete" -> "FAKECLONE1:1_start_0 remote1" [ style = bold] +"probe_complete" -> "FAKECLONE2:0_start_0 18node3" [ style = bold] "probe_complete" -> "FAKECLONE2:1_start_0 18node1" [ style = bold] "probe_complete" -> "FAKECLONE2:2_start_0 18node2" [ style = bold] "probe_complete" -> "FAKECLONE2:3_start_0 18node4" [ style = bold] "probe_complete" -> "FAKECLONE2:4_start_0 remote1" [ style = bold] -"probe_complete" -> "FAKECLONE2:5_start_0 18node3" [ style = bold] +"probe_complete" -> "shooter_start_0 18node2" [ style = bold] "probe_complete" [ style=bold color="green" fontcolor="orange"] -"probe_nodes_complete" -> "remote1_start_0 18builder" [ style = bold] +"probe_nodes_complete" -> "remote1_start_0 18node1" [ style = bold] "probe_nodes_complete" [ style=bold color="green" fontcolor="orange"] +"remote1_monitor_0 18node1" -> "probe_complete 18node1" [ style = bold] +"remote1_monitor_0 18node1" [ style=bold color="green" fontcolor="black"] +"remote1_monitor_0 18node2" -> "probe_complete 18node2" [ style = bold] +"remote1_monitor_0 18node2" [ style=bold color="green" fontcolor="black"] "remote1_monitor_0 18node3" -> "probe_complete 18node3" [ style = bold] "remote1_monitor_0 18node3" [ style=bold color="green" fontcolor="black"] "remote1_monitor_0 18node4" -> "probe_complete 18node4" [ style = bold] "remote1_monitor_0 18node4" [ style=bold color="green" fontcolor="black"] -"remote1_monitor_60000 18builder" [ style=bold color="green" fontcolor="black"] -"remote1_start_0 18builder" -> "FAKE5_monitor_0 remote1" [ style = bold] -"remote1_start_0 18builder" -> "FAKE5_monitor_60000 remote1" [ style = bold] -"remote1_start_0 18builder" -> "FAKE5_start_0 remote1" [ style = bold] -"remote1_start_0 18builder" -> "FAKECLONE1:4_monitor_0 remote1" [ style = bold] -"remote1_start_0 18builder" -> "FAKECLONE1:4_monitor_60000 remote1" [ style = bold] -"remote1_start_0 18builder" -> "FAKECLONE1:4_start_0 remote1" [ style = bold] -"remote1_start_0 18builder" -> "FAKECLONE2:4_monitor_0 remote1" [ style = bold] -"remote1_start_0 18builder" -> "FAKECLONE2:4_monitor_60000 remote1" [ style = bold] -"remote1_start_0 18builder" -> "FAKECLONE2:4_start_0 remote1" [ style = bold] -"remote1_start_0 18builder" -> "remote1_monitor_60000 18builder" [ style = bold] -"remote1_start_0 18builder" [ style=bold color="green" fontcolor="black"] +"remote1_monitor_60000 18node1" [ style=bold color="green" fontcolor="black"] +"remote1_start_0 18node1" -> "FAKE5_monitor_0 remote1" [ style = bold] +"remote1_start_0 18node1" -> "FAKE5_monitor_60000 remote1" [ style = bold] +"remote1_start_0 18node1" -> "FAKE5_start_0 remote1" [ style = bold] +"remote1_start_0 18node1" -> "FAKECLONE1:1_monitor_0 remote1" [ style = bold] +"remote1_start_0 18node1" -> "FAKECLONE1:1_monitor_60000 remote1" [ style = bold] +"remote1_start_0 18node1" -> "FAKECLONE1:1_start_0 remote1" [ style = bold] +"remote1_start_0 18node1" -> "FAKECLONE2:4_monitor_0 remote1" [ style = bold] +"remote1_start_0 18node1" -> "FAKECLONE2:4_monitor_60000 remote1" [ style = bold] +"remote1_start_0 18node1" -> "FAKECLONE2:4_start_0 remote1" [ style = bold] +"remote1_start_0 18node1" -> "remote1_monitor_60000 18node1" [ style = bold] +"remote1_start_0 18node1" [ style=bold color="green" fontcolor="black"] +"shooter_monitor_0 18node1" -> "probe_complete 18node1" [ style = bold] +"shooter_monitor_0 18node1" [ style=bold color="green" fontcolor="black"] +"shooter_monitor_0 18node2" -> "probe_complete 18node2" [ style = bold] +"shooter_monitor_0 18node2" [ style=bold color="green" fontcolor="black"] "shooter_monitor_0 18node3" -> "probe_complete 18node3" [ style = bold] "shooter_monitor_0 18node3" [ style=bold color="green" fontcolor="black"] "shooter_monitor_0 18node4" -> "probe_complete 18node4" [ style = bold] "shooter_monitor_0 18node4" [ style=bold color="green" fontcolor="black"] +"shooter_monitor_60000 18node2" [ style=bold color="green" fontcolor="black"] +"shooter_start_0 18node2" -> "shooter_monitor_60000 18node2" [ style = bold] +"shooter_start_0 18node2" [ style=bold color="green" fontcolor="black"] } diff --git a/pengine/test10/resource-discovery.exp b/pengine/test10/resource-discovery.exp index 2770f4e..5459bd7 100644 --- a/pengine/test10/resource-discovery.exp +++ b/pengine/test10/resource-discovery.exp @@ -1,52 +1,52 @@ - + - + - + + + + + - + - + - + + + + + - - - + + + - - - - - + - - - + + + - - - - - + - - + + @@ -54,8 +54,8 @@ - - + + @@ -63,34 +63,34 @@ - - + + - + - - + + - + - - + + @@ -98,8 +98,8 @@ - - + + @@ -107,8 +107,8 @@ - - + + @@ -116,8 +116,8 @@ - - + + @@ -125,95 +125,110 @@ - + - - - - - - - - - - + - + - - + + - + + + + + + + + + + - + - + - + - - - + + + - + - + + + + + + + + + + + + + + + + + + + - + - - - - + - + - + - + - + @@ -222,49 +237,33 @@ - + - + - + - - - - - - - - - - - - - - - - - + - + - + - + @@ -273,63 +272,54 @@ - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - + @@ -338,7 +328,7 @@ - + @@ -347,7 +337,7 @@ - + @@ -356,7 +346,7 @@ - + @@ -365,517 +355,480 @@ - + - + - + - + - + - + - + - - - + + + - - - - - + - + - + - + - + - - - + + + - + - - - - - - - - - - - + - + - + - - - + + + - + - + - - - - + + + - + - + + + + + + + + + + + + - - - + + + - - - - + - - - + + + - + - - - - + - - - + + + - - - - - + - - - + + + - + - - - + + + - + - + - + - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + - + - + - - - - - - - - - + - - - + + + - + - + - - - + + + - + - + - + - - - + + + - + - - - + + + - + + + + - + - - - + + + - + + + + - + - - - - - - - - - - - - + + + - + - + - - - - + + + - + + + + + + + - + + + + + + + - - - - + + + - - - - - + - - - - + + + - + + + + - + - - - - + + + - - - + + + - - - - + - - - + + + - - - - + - + - - - + + + - - - - - + - - - + + + - - - - - + - - - + + + - - - - + - - - + + + - - - - - - - - - - - - + - + - - - - - - - - - - + + + + + + + + + + - - - + + + + - + - + - + - + @@ -908,19 +861,16 @@ - + - - - - + - + @@ -929,112 +879,100 @@ - + - + - + - + + + + - - - - - - - - - - + - + - + - + - + - + - + - + - - - - - - - - - - + - + - + - + - + - + - + - + + + + + + + + + + - + - + - - - - - - - + diff --git a/pengine/test10/resource-discovery.scores b/pengine/test10/resource-discovery.scores index e1fa78e..9b56b96 100644 --- a/pengine/test10/resource-discovery.scores +++ b/pengine/test10/resource-discovery.scores @@ -1,197 +1,169 @@ Allocation scores: -clone_color: FAKECLONE1-clone allocation score on 18builder: 0 clone_color: FAKECLONE1-clone allocation score on 18node1: 0 -clone_color: FAKECLONE1-clone allocation score on 18node2: 0 -clone_color: FAKECLONE1-clone allocation score on 18node3: 0 -clone_color: FAKECLONE1-clone allocation score on 18node4: 0 +clone_color: FAKECLONE1-clone allocation score on 18node2: -INFINITY +clone_color: FAKECLONE1-clone allocation score on 18node3: -INFINITY +clone_color: FAKECLONE1-clone allocation score on 18node4: -INFINITY clone_color: FAKECLONE1-clone allocation score on remote1: 0 -clone_color: FAKECLONE1:0 allocation score on 18builder: 0 clone_color: FAKECLONE1:0 allocation score on 18node1: 0 -clone_color: FAKECLONE1:0 allocation score on 18node2: 0 -clone_color: FAKECLONE1:0 allocation score on 18node3: 0 -clone_color: FAKECLONE1:0 allocation score on 18node4: 0 +clone_color: FAKECLONE1:0 allocation score on 18node2: -INFINITY +clone_color: FAKECLONE1:0 allocation score on 18node3: -INFINITY +clone_color: FAKECLONE1:0 allocation score on 18node4: -INFINITY clone_color: FAKECLONE1:0 allocation score on remote1: 0 -clone_color: FAKECLONE1:1 allocation score on 18builder: 0 clone_color: FAKECLONE1:1 allocation score on 18node1: 0 -clone_color: FAKECLONE1:1 allocation score on 18node2: 0 -clone_color: FAKECLONE1:1 allocation score on 18node3: 0 -clone_color: FAKECLONE1:1 allocation score on 18node4: 0 +clone_color: FAKECLONE1:1 allocation score on 18node2: -INFINITY +clone_color: FAKECLONE1:1 allocation score on 18node3: -INFINITY +clone_color: FAKECLONE1:1 allocation score on 18node4: -INFINITY clone_color: FAKECLONE1:1 allocation score on remote1: 0 -clone_color: FAKECLONE1:2 allocation score on 18builder: 0 clone_color: FAKECLONE1:2 allocation score on 18node1: 0 -clone_color: FAKECLONE1:2 allocation score on 18node2: 0 -clone_color: FAKECLONE1:2 allocation score on 18node3: 0 -clone_color: FAKECLONE1:2 allocation score on 18node4: 0 +clone_color: FAKECLONE1:2 allocation score on 18node2: -INFINITY +clone_color: FAKECLONE1:2 allocation score on 18node3: -INFINITY +clone_color: FAKECLONE1:2 allocation score on 18node4: -INFINITY clone_color: FAKECLONE1:2 allocation score on remote1: 0 -clone_color: FAKECLONE1:3 allocation score on 18builder: 0 clone_color: FAKECLONE1:3 allocation score on 18node1: 0 -clone_color: FAKECLONE1:3 allocation score on 18node2: 0 -clone_color: FAKECLONE1:3 allocation score on 18node3: 0 -clone_color: FAKECLONE1:3 allocation score on 18node4: 0 +clone_color: FAKECLONE1:3 allocation score on 18node2: -INFINITY +clone_color: FAKECLONE1:3 allocation score on 18node3: -INFINITY +clone_color: FAKECLONE1:3 allocation score on 18node4: -INFINITY clone_color: FAKECLONE1:3 allocation score on remote1: 0 -clone_color: FAKECLONE1:4 allocation score on 18builder: 0 clone_color: FAKECLONE1:4 allocation score on 18node1: 0 -clone_color: FAKECLONE1:4 allocation score on 18node2: 0 -clone_color: FAKECLONE1:4 allocation score on 18node3: 0 -clone_color: FAKECLONE1:4 allocation score on 18node4: 0 +clone_color: FAKECLONE1:4 allocation score on 18node2: -INFINITY +clone_color: FAKECLONE1:4 allocation score on 18node3: -INFINITY +clone_color: FAKECLONE1:4 allocation score on 18node4: -INFINITY clone_color: FAKECLONE1:4 allocation score on remote1: 0 -clone_color: FAKECLONE1:5 allocation score on 18builder: 0 -clone_color: FAKECLONE1:5 allocation score on 18node1: 0 -clone_color: FAKECLONE1:5 allocation score on 18node2: 0 -clone_color: FAKECLONE1:5 allocation score on 18node3: 0 -clone_color: FAKECLONE1:5 allocation score on 18node4: 0 -clone_color: FAKECLONE1:5 allocation score on remote1: 0 -clone_color: FAKECLONE2-clone allocation score on 18builder: 0 clone_color: FAKECLONE2-clone allocation score on 18node1: 0 clone_color: FAKECLONE2-clone allocation score on 18node2: 0 clone_color: FAKECLONE2-clone allocation score on 18node3: 0 clone_color: FAKECLONE2-clone allocation score on 18node4: 0 clone_color: FAKECLONE2-clone allocation score on remote1: 0 -clone_color: FAKECLONE2:0 allocation score on 18builder: 0 clone_color: FAKECLONE2:0 allocation score on 18node1: 0 clone_color: FAKECLONE2:0 allocation score on 18node2: 0 clone_color: FAKECLONE2:0 allocation score on 18node3: 0 clone_color: FAKECLONE2:0 allocation score on 18node4: 0 clone_color: FAKECLONE2:0 allocation score on remote1: 0 -clone_color: FAKECLONE2:1 allocation score on 18builder: 0 clone_color: FAKECLONE2:1 allocation score on 18node1: 0 clone_color: FAKECLONE2:1 allocation score on 18node2: 0 clone_color: FAKECLONE2:1 allocation score on 18node3: 0 clone_color: FAKECLONE2:1 allocation score on 18node4: 0 clone_color: FAKECLONE2:1 allocation score on remote1: 0 -clone_color: FAKECLONE2:2 allocation score on 18builder: 0 clone_color: FAKECLONE2:2 allocation score on 18node1: 0 clone_color: FAKECLONE2:2 allocation score on 18node2: 0 clone_color: FAKECLONE2:2 allocation score on 18node3: 0 clone_color: FAKECLONE2:2 allocation score on 18node4: 0 clone_color: FAKECLONE2:2 allocation score on remote1: 0 -clone_color: FAKECLONE2:3 allocation score on 18builder: 0 clone_color: FAKECLONE2:3 allocation score on 18node1: 0 clone_color: FAKECLONE2:3 allocation score on 18node2: 0 clone_color: FAKECLONE2:3 allocation score on 18node3: 0 clone_color: FAKECLONE2:3 allocation score on 18node4: 0 clone_color: FAKECLONE2:3 allocation score on remote1: 0 -clone_color: FAKECLONE2:4 allocation score on 18builder: 0 clone_color: FAKECLONE2:4 allocation score on 18node1: 0 clone_color: FAKECLONE2:4 allocation score on 18node2: 0 clone_color: FAKECLONE2:4 allocation score on 18node3: 0 clone_color: FAKECLONE2:4 allocation score on 18node4: 0 clone_color: FAKECLONE2:4 allocation score on remote1: 0 -clone_color: FAKECLONE2:5 allocation score on 18builder: 0 -clone_color: FAKECLONE2:5 allocation score on 18node1: 0 -clone_color: FAKECLONE2:5 allocation score on 18node2: 0 -clone_color: FAKECLONE2:5 allocation score on 18node3: 0 -clone_color: FAKECLONE2:5 allocation score on 18node4: 0 -clone_color: FAKECLONE2:5 allocation score on remote1: 0 -native_color: FAKE1 allocation score on 18builder: 0 -native_color: FAKE1 allocation score on 18node1: 0 -native_color: FAKE1 allocation score on 18node2: 0 -native_color: FAKE1 allocation score on 18node3: 0 +group_color: FAKE6 allocation score on 18node1: 0 +group_color: FAKE6 allocation score on 18node2: 0 +group_color: FAKE6 allocation score on 18node3: -INFINITY +group_color: FAKE6 allocation score on 18node4: -INFINITY +group_color: FAKE6 allocation score on remote1: -INFINITY +group_color: FAKE7 allocation score on 18node1: 0 +group_color: FAKE7 allocation score on 18node2: 0 +group_color: FAKE7 allocation score on 18node3: -INFINITY +group_color: FAKE7 allocation score on 18node4: -INFINITY +group_color: FAKE7 allocation score on remote1: -INFINITY +group_color: FAKEGROUP allocation score on 18node1: 0 +group_color: FAKEGROUP allocation score on 18node2: 0 +group_color: FAKEGROUP allocation score on 18node3: -INFINITY +group_color: FAKEGROUP allocation score on 18node4: -INFINITY +group_color: FAKEGROUP allocation score on remote1: -INFINITY +native_color: FAKE1 allocation score on 18node1: -INFINITY +native_color: FAKE1 allocation score on 18node2: -INFINITY +native_color: FAKE1 allocation score on 18node3: -INFINITY native_color: FAKE1 allocation score on 18node4: 0 native_color: FAKE1 allocation score on remote1: -INFINITY -native_color: FAKE2 allocation score on 18builder: 0 -native_color: FAKE2 allocation score on 18node1: 0 -native_color: FAKE2 allocation score on 18node2: -INFINITY -native_color: FAKE2 allocation score on 18node3: 0 -native_color: FAKE2 allocation score on 18node4: 0 -native_color: FAKE2 allocation score on remote1: 0 -native_color: FAKE3 allocation score on 18builder: 0 -native_color: FAKE3 allocation score on 18node1: 0 -native_color: FAKE3 allocation score on 18node2: 0 +native_color: FAKE2 allocation score on 18node1: 10 +native_color: FAKE2 allocation score on 18node2: 100 +native_color: FAKE2 allocation score on 18node3: -INFINITY +native_color: FAKE2 allocation score on 18node4: -INFINITY +native_color: FAKE2 allocation score on remote1: -INFINITY +native_color: FAKE3 allocation score on 18node1: -INFINITY +native_color: FAKE3 allocation score on 18node2: -INFINITY native_color: FAKE3 allocation score on 18node3: INFINITY -native_color: FAKE3 allocation score on 18node4: 0 -native_color: FAKE3 allocation score on remote1: 0 -native_color: FAKE4 allocation score on 18builder: 0 -native_color: FAKE4 allocation score on 18node1: 0 -native_color: FAKE4 allocation score on 18node2: 0 -native_color: FAKE4 allocation score on 18node3: 0 +native_color: FAKE3 allocation score on 18node4: -INFINITY +native_color: FAKE3 allocation score on remote1: -INFINITY +native_color: FAKE4 allocation score on 18node1: -INFINITY +native_color: FAKE4 allocation score on 18node2: -INFINITY +native_color: FAKE4 allocation score on 18node3: -INFINITY native_color: FAKE4 allocation score on 18node4: 0 -native_color: FAKE4 allocation score on remote1: 0 -native_color: FAKE5 allocation score on 18builder: 0 +native_color: FAKE4 allocation score on remote1: -INFINITY native_color: FAKE5 allocation score on 18node1: 0 native_color: FAKE5 allocation score on 18node2: 0 native_color: FAKE5 allocation score on 18node3: 0 native_color: FAKE5 allocation score on 18node4: 0 native_color: FAKE5 allocation score on remote1: 0 -native_color: FAKECLONE1:0 allocation score on 18builder: 0 +native_color: FAKE6 allocation score on 18node1: 0 +native_color: FAKE6 allocation score on 18node2: 0 +native_color: FAKE6 allocation score on 18node3: -INFINITY +native_color: FAKE6 allocation score on 18node4: -INFINITY +native_color: FAKE6 allocation score on remote1: -INFINITY +native_color: FAKE7 allocation score on 18node1: 0 +native_color: FAKE7 allocation score on 18node2: -INFINITY +native_color: FAKE7 allocation score on 18node3: -INFINITY +native_color: FAKE7 allocation score on 18node4: -INFINITY +native_color: FAKE7 allocation score on remote1: -INFINITY native_color: FAKECLONE1:0 allocation score on 18node1: 0 -native_color: FAKECLONE1:0 allocation score on 18node2: 0 -native_color: FAKECLONE1:0 allocation score on 18node3: 0 -native_color: FAKECLONE1:0 allocation score on 18node4: 0 +native_color: FAKECLONE1:0 allocation score on 18node2: -INFINITY +native_color: FAKECLONE1:0 allocation score on 18node3: -INFINITY +native_color: FAKECLONE1:0 allocation score on 18node4: -INFINITY native_color: FAKECLONE1:0 allocation score on remote1: 0 -native_color: FAKECLONE1:1 allocation score on 18builder: -INFINITY -native_color: FAKECLONE1:1 allocation score on 18node1: 0 -native_color: FAKECLONE1:1 allocation score on 18node2: 0 -native_color: FAKECLONE1:1 allocation score on 18node3: 0 -native_color: FAKECLONE1:1 allocation score on 18node4: 0 +native_color: FAKECLONE1:1 allocation score on 18node1: -INFINITY +native_color: FAKECLONE1:1 allocation score on 18node2: -INFINITY +native_color: FAKECLONE1:1 allocation score on 18node3: -INFINITY +native_color: FAKECLONE1:1 allocation score on 18node4: -INFINITY native_color: FAKECLONE1:1 allocation score on remote1: 0 -native_color: FAKECLONE1:2 allocation score on 18builder: -INFINITY native_color: FAKECLONE1:2 allocation score on 18node1: -INFINITY -native_color: FAKECLONE1:2 allocation score on 18node2: 0 -native_color: FAKECLONE1:2 allocation score on 18node3: 0 -native_color: FAKECLONE1:2 allocation score on 18node4: 0 -native_color: FAKECLONE1:2 allocation score on remote1: 0 -native_color: FAKECLONE1:3 allocation score on 18builder: -INFINITY +native_color: FAKECLONE1:2 allocation score on 18node2: -INFINITY +native_color: FAKECLONE1:2 allocation score on 18node3: -INFINITY +native_color: FAKECLONE1:2 allocation score on 18node4: -INFINITY +native_color: FAKECLONE1:2 allocation score on remote1: -INFINITY native_color: FAKECLONE1:3 allocation score on 18node1: -INFINITY native_color: FAKECLONE1:3 allocation score on 18node2: -INFINITY -native_color: FAKECLONE1:3 allocation score on 18node3: 0 -native_color: FAKECLONE1:3 allocation score on 18node4: 0 -native_color: FAKECLONE1:3 allocation score on remote1: 0 -native_color: FAKECLONE1:4 allocation score on 18builder: -INFINITY +native_color: FAKECLONE1:3 allocation score on 18node3: -INFINITY +native_color: FAKECLONE1:3 allocation score on 18node4: -INFINITY +native_color: FAKECLONE1:3 allocation score on remote1: -INFINITY native_color: FAKECLONE1:4 allocation score on 18node1: -INFINITY native_color: FAKECLONE1:4 allocation score on 18node2: -INFINITY -native_color: FAKECLONE1:4 allocation score on 18node3: 0 +native_color: FAKECLONE1:4 allocation score on 18node3: -INFINITY native_color: FAKECLONE1:4 allocation score on 18node4: -INFINITY -native_color: FAKECLONE1:4 allocation score on remote1: 0 -native_color: FAKECLONE1:5 allocation score on 18builder: -INFINITY -native_color: FAKECLONE1:5 allocation score on 18node1: -INFINITY -native_color: FAKECLONE1:5 allocation score on 18node2: -INFINITY -native_color: FAKECLONE1:5 allocation score on 18node3: 0 -native_color: FAKECLONE1:5 allocation score on 18node4: -INFINITY -native_color: FAKECLONE1:5 allocation score on remote1: -INFINITY -native_color: FAKECLONE2:0 allocation score on 18builder: 0 +native_color: FAKECLONE1:4 allocation score on remote1: -INFINITY native_color: FAKECLONE2:0 allocation score on 18node1: 0 native_color: FAKECLONE2:0 allocation score on 18node2: 0 native_color: FAKECLONE2:0 allocation score on 18node3: 0 native_color: FAKECLONE2:0 allocation score on 18node4: 0 native_color: FAKECLONE2:0 allocation score on remote1: 0 -native_color: FAKECLONE2:1 allocation score on 18builder: -INFINITY native_color: FAKECLONE2:1 allocation score on 18node1: 0 native_color: FAKECLONE2:1 allocation score on 18node2: 0 -native_color: FAKECLONE2:1 allocation score on 18node3: 0 +native_color: FAKECLONE2:1 allocation score on 18node3: -INFINITY native_color: FAKECLONE2:1 allocation score on 18node4: 0 native_color: FAKECLONE2:1 allocation score on remote1: 0 -native_color: FAKECLONE2:2 allocation score on 18builder: -INFINITY native_color: FAKECLONE2:2 allocation score on 18node1: -INFINITY native_color: FAKECLONE2:2 allocation score on 18node2: 0 -native_color: FAKECLONE2:2 allocation score on 18node3: 0 +native_color: FAKECLONE2:2 allocation score on 18node3: -INFINITY native_color: FAKECLONE2:2 allocation score on 18node4: 0 native_color: FAKECLONE2:2 allocation score on remote1: 0 -native_color: FAKECLONE2:3 allocation score on 18builder: -INFINITY native_color: FAKECLONE2:3 allocation score on 18node1: -INFINITY native_color: FAKECLONE2:3 allocation score on 18node2: -INFINITY -native_color: FAKECLONE2:3 allocation score on 18node3: 0 +native_color: FAKECLONE2:3 allocation score on 18node3: -INFINITY native_color: FAKECLONE2:3 allocation score on 18node4: 0 native_color: FAKECLONE2:3 allocation score on remote1: 0 -native_color: FAKECLONE2:4 allocation score on 18builder: -INFINITY native_color: FAKECLONE2:4 allocation score on 18node1: -INFINITY native_color: FAKECLONE2:4 allocation score on 18node2: -INFINITY -native_color: FAKECLONE2:4 allocation score on 18node3: 0 +native_color: FAKECLONE2:4 allocation score on 18node3: -INFINITY native_color: FAKECLONE2:4 allocation score on 18node4: -INFINITY native_color: FAKECLONE2:4 allocation score on remote1: 0 -native_color: FAKECLONE2:5 allocation score on 18builder: -INFINITY -native_color: FAKECLONE2:5 allocation score on 18node1: -INFINITY -native_color: FAKECLONE2:5 allocation score on 18node2: -INFINITY -native_color: FAKECLONE2:5 allocation score on 18node3: 0 -native_color: FAKECLONE2:5 allocation score on 18node4: -INFINITY -native_color: FAKECLONE2:5 allocation score on remote1: -INFINITY -native_color: remote1 allocation score on 18builder: 0 native_color: remote1 allocation score on 18node1: 0 native_color: remote1 allocation score on 18node2: 0 native_color: remote1 allocation score on 18node3: 0 native_color: remote1 allocation score on 18node4: 0 native_color: remote1 allocation score on remote1: -INFINITY -native_color: shooter allocation score on 18builder: 0 native_color: shooter allocation score on 18node1: 0 native_color: shooter allocation score on 18node2: 0 native_color: shooter allocation score on 18node3: 0 diff --git a/pengine/test10/resource-discovery.summary b/pengine/test10/resource-discovery.summary index af0e5b3..e3d23a5 100644 --- a/pengine/test10/resource-discovery.summary +++ b/pengine/test10/resource-discovery.summary @@ -1,124 +1,128 @@ Current cluster status: -Online: [ 18builder 18node1 18node2 18node3 18node4 ] +Online: [ 18node1 18node2 18node3 18node4 ] RemoteOFFLINE: [ remote1 ] - shooter (stonith:fence_xvm): Started 18node1 + shooter (stonith:fence_xvm): Stopped remote1 (ocf::pacemaker:remote): Stopped FAKE1 (ocf::heartbeat:Dummy): Stopped - FAKE2 (ocf::heartbeat:Dummy): Started 18node2 - FAKE3 (ocf::heartbeat:Dummy): Started 18builder - FAKE4 (ocf::heartbeat:Dummy): Started 18node1 + FAKE2 (ocf::heartbeat:Dummy): Stopped + FAKE3 (ocf::heartbeat:Dummy): Stopped + FAKE4 (ocf::heartbeat:Dummy): Stopped FAKE5 (ocf::heartbeat:Dummy): Stopped Clone Set: FAKECLONE1-clone [FAKECLONE1] - Stopped: [ 18builder 18node1 18node2 18node3 18node4 remote1 ] + Stopped: [ 18node1 18node2 18node3 18node4 remote1 ] Clone Set: FAKECLONE2-clone [FAKECLONE2] - Stopped: [ 18builder 18node1 18node2 18node3 18node4 remote1 ] + Stopped: [ 18node1 18node2 18node3 18node4 remote1 ] + Resource Group: FAKEGROUP + FAKE6 (ocf::heartbeat:Dummy): Stopped + FAKE7 (ocf::heartbeat:Dummy): Stopped Transition Summary: - * Start remote1 (18builder) - * Start FAKE1 (18node2) - * Move FAKE2 (Started 18node2 -> 18node3) - * Move FAKE3 (Started 18builder -> 18node3) - * Move FAKE4 (Started 18node1 -> 18node4) + * Start shooter (18node2) + * Start remote1 (18node1) + * Start FAKE1 (18node4) + * Start FAKE2 (18node2) + * Start FAKE3 (18node3) + * Start FAKE4 (18node4) * Start FAKE5 (remote1) - * Start FAKECLONE1:0 (18builder) - * Start FAKECLONE1:1 (18node1) - * Start FAKECLONE1:2 (18node2) - * Start FAKECLONE1:3 (18node4) - * Start FAKECLONE1:4 (remote1) - * Start FAKECLONE1:5 (18node3) - * Start FAKECLONE2:0 (18builder) + * Start FAKECLONE1:0 (18node1) + * Start FAKECLONE1:1 (remote1) + * Start FAKECLONE2:0 (18node3) * Start FAKECLONE2:1 (18node1) * Start FAKECLONE2:2 (18node2) * Start FAKECLONE2:3 (18node4) * Start FAKECLONE2:4 (remote1) - * Start FAKECLONE2:5 (18node3) + * Start FAKE6 (18node1) + * Start FAKE7 (18node1) Executing cluster transition: * Resource action: shooter monitor on 18node4 * Resource action: shooter monitor on 18node3 + * Resource action: shooter monitor on 18node2 + * Resource action: shooter monitor on 18node1 * Resource action: remote1 monitor on 18node4 * Resource action: remote1 monitor on 18node3 + * Resource action: remote1 monitor on 18node2 + * Resource action: remote1 monitor on 18node1 * Resource action: FAKE1 monitor on 18node4 - * Resource action: FAKE1 monitor on 18node3 - * Resource action: FAKE1 monitor on 18node2 - * Resource action: FAKE1 monitor on 18node1 - * Resource action: FAKE1 monitor on 18builder + * Resource action: FAKE2 monitor on 18node2 + * Resource action: FAKE2 monitor on 18node1 * Resource action: FAKE3 monitor on 18node3 * Resource action: FAKE4 monitor on 18node4 * Resource action: FAKE5 monitor on 18node4 * Resource action: FAKE5 monitor on 18node3 * Resource action: FAKE5 monitor on 18node2 * Resource action: FAKE5 monitor on 18node1 - * Resource action: FAKE5 monitor on 18builder + * Resource action: FAKECLONE1:0 monitor on 18node1 * Pseudo action: FAKECLONE1-clone_start_0 - * Resource action: FAKECLONE2:0 monitor on 18builder + * Resource action: FAKECLONE2:0 monitor on 18node3 * Resource action: FAKECLONE2:1 monitor on 18node1 * Resource action: FAKECLONE2:3 monitor on 18node4 - * Resource action: FAKECLONE2:5 monitor on 18node3 * Pseudo action: FAKECLONE2-clone_start_0 + * Pseudo action: FAKEGROUP_start_0 + * Resource action: FAKE6 monitor on 18node2 + * Resource action: FAKE6 monitor on 18node1 + * Resource action: FAKE7 monitor on 18node2 + * Resource action: FAKE7 monitor on 18node1 * Pseudo action: probe_nodes_complete - * Resource action: remote1 start on 18builder + * Resource action: remote1 start on 18node1 * Resource action: FAKE5 monitor on remote1 - * Resource action: FAKECLONE1:4 monitor on remote1 + * Resource action: FAKECLONE1:1 monitor on remote1 * Resource action: FAKECLONE2:4 monitor on remote1 * Pseudo action: probe_complete - * Resource action: remote1 monitor=60000 on 18builder - * Resource action: FAKE1 start on 18node2 - * Resource action: FAKE2 stop on 18node2 - * Resource action: FAKE3 stop on 18builder - * Resource action: FAKE4 stop on 18node1 + * Resource action: shooter start on 18node2 + * Resource action: remote1 monitor=60000 on 18node1 + * Resource action: FAKE1 start on 18node4 + * Resource action: FAKE2 start on 18node2 + * Resource action: FAKE3 start on 18node3 + * Resource action: FAKE4 start on 18node4 * Resource action: FAKE5 start on remote1 - * Resource action: FAKECLONE1:0 start on 18builder - * Resource action: FAKECLONE1:1 start on 18node1 - * Resource action: FAKECLONE1:2 start on 18node2 - * Resource action: FAKECLONE1:3 start on 18node4 - * Resource action: FAKECLONE1:4 start on remote1 - * Resource action: FAKECLONE1:5 start on 18node3 + * Resource action: FAKECLONE1:0 start on 18node1 + * Resource action: FAKECLONE1:1 start on remote1 * Pseudo action: FAKECLONE1-clone_running_0 - * Resource action: FAKECLONE2:0 start on 18builder + * Resource action: FAKECLONE2:0 start on 18node3 * Resource action: FAKECLONE2:1 start on 18node1 * Resource action: FAKECLONE2:2 start on 18node2 * Resource action: FAKECLONE2:3 start on 18node4 * Resource action: FAKECLONE2:4 start on remote1 - * Resource action: FAKECLONE2:5 start on 18node3 * Pseudo action: FAKECLONE2-clone_running_0 - * Pseudo action: all_stopped - * Resource action: FAKE1 monitor=60000 on 18node2 - * Resource action: FAKE2 start on 18node3 - * Resource action: FAKE3 start on 18node3 - * Resource action: FAKE4 start on 18node4 + * Resource action: FAKE6 start on 18node1 + * Resource action: FAKE7 start on 18node1 + * Resource action: shooter monitor=60000 on 18node2 + * Resource action: FAKE1 monitor=60000 on 18node4 + * Resource action: FAKE2 monitor=60000 on 18node2 + * Resource action: FAKE3 monitor=60000 on 18node3 + * Resource action: FAKE4 monitor=60000 on 18node4 * Resource action: FAKE5 monitor=60000 on remote1 - * Resource action: FAKECLONE1:0 monitor=60000 on 18builder - * Resource action: FAKECLONE1:1 monitor=60000 on 18node1 - * Resource action: FAKECLONE1:2 monitor=60000 on 18node2 - * Resource action: FAKECLONE1:3 monitor=60000 on 18node4 - * Resource action: FAKECLONE1:4 monitor=60000 on remote1 - * Resource action: FAKECLONE1:5 monitor=60000 on 18node3 - * Resource action: FAKECLONE2:0 monitor=60000 on 18builder + * Resource action: FAKECLONE1:0 monitor=60000 on 18node1 + * Resource action: FAKECLONE1:1 monitor=60000 on remote1 + * Resource action: FAKECLONE2:0 monitor=60000 on 18node3 * Resource action: FAKECLONE2:1 monitor=60000 on 18node1 * Resource action: FAKECLONE2:2 monitor=60000 on 18node2 * Resource action: FAKECLONE2:3 monitor=60000 on 18node4 * Resource action: FAKECLONE2:4 monitor=60000 on remote1 - * Resource action: FAKECLONE2:5 monitor=60000 on 18node3 - * Resource action: FAKE2 monitor=60000 on 18node3 - * Resource action: FAKE3 monitor=60000 on 18node3 - * Resource action: FAKE4 monitor=60000 on 18node4 + * Pseudo action: FAKEGROUP_running_0 + * Resource action: FAKE6 monitor=10000 on 18node1 + * Resource action: FAKE7 monitor=10000 on 18node1 Revised cluster status: -Online: [ 18builder 18node1 18node2 18node3 18node4 ] +Online: [ 18node1 18node2 18node3 18node4 ] RemoteOnline: [ remote1 ] - shooter (stonith:fence_xvm): Started 18node1 - remote1 (ocf::pacemaker:remote): Started 18builder - FAKE1 (ocf::heartbeat:Dummy): Started 18node2 - FAKE2 (ocf::heartbeat:Dummy): Started 18node3 + shooter (stonith:fence_xvm): Started 18node2 + remote1 (ocf::pacemaker:remote): Started 18node1 + FAKE1 (ocf::heartbeat:Dummy): Started 18node4 + FAKE2 (ocf::heartbeat:Dummy): Started 18node2 FAKE3 (ocf::heartbeat:Dummy): Started 18node3 FAKE4 (ocf::heartbeat:Dummy): Started 18node4 FAKE5 (ocf::heartbeat:Dummy): Started remote1 Clone Set: FAKECLONE1-clone [FAKECLONE1] - Started: [ 18builder 18node1 18node2 18node3 18node4 remote1 ] + Started: [ 18node1 remote1 ] + Stopped: [ 18node2 18node3 18node4 ] Clone Set: FAKECLONE2-clone [FAKECLONE2] - Started: [ 18builder 18node1 18node2 18node3 18node4 remote1 ] + Started: [ 18node1 18node2 18node3 18node4 remote1 ] + Resource Group: FAKEGROUP + FAKE6 (ocf::heartbeat:Dummy): Started 18node1 + FAKE7 (ocf::heartbeat:Dummy): Started 18node1 diff --git a/pengine/test10/resource-discovery.xml b/pengine/test10/resource-discovery.xml index 5836804..8b517df 100644 --- a/pengine/test10/resource-discovery.xml +++ b/pengine/test10/resource-discovery.xml @@ -1,4 +1,4 @@ - + @@ -11,7 +11,6 @@ - @@ -29,16 +28,14 @@ - - + - - + @@ -77,109 +74,70 @@ + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - + - - - - - - - - - - - - - - - - - - - - + - - - - - + - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - + + + + + + + + diff --git a/tools/Makefile.am b/tools/Makefile.am index 5142b29..74b69e3 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -77,7 +77,7 @@ crm_node_SOURCES = crm_node.c crm_node_LDADD = $(top_builddir)/lib/cluster/libcrmcluster.la \ $(COMMONLIBS) $(CLUSTERLIBS) -crm_simulate_SOURCES = crm_simulate.c +crm_simulate_SOURCES = crm_simulate.c fake_transition.c crm_simulate_CFLAGS = -I$(top_srcdir)/pengine crm_simulate_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \ @@ -105,12 +105,14 @@ crm_verify_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \ crm_attribute_SOURCES = crm_attribute.c crm_attribute_LDADD = $(top_builddir)/lib/cluster/libcrmcluster.la $(COMMONLIBS) -crm_resource_SOURCES = crm_resource.c -crm_resource_LDADD = $(top_builddir)/lib/pengine/libpe_rules.la \ - $(top_builddir)/lib/lrmd/liblrmd.la \ - $(top_builddir)/lib/services/libcrmservice.la \ - $(top_builddir)/lib/pengine/libpe_status.la \ - $(top_builddir)/pengine/libpengine.la \ +crm_resource_SOURCES = crm_resource.c fake_transition.c +crm_resource_CFLAGS = -I$(top_srcdir)/pengine +crm_resource_LDADD = $(top_builddir)/lib/pengine/libpe_rules.la \ + $(top_builddir)/lib/lrmd/liblrmd.la \ + $(top_builddir)/lib/services/libcrmservice.la \ + $(top_builddir)/lib/pengine/libpe_status.la \ + $(top_builddir)/pengine/libpengine.la \ + $(top_builddir)/lib/transition/libtransitioner.la \ $(COMMONLIBS) iso8601_SOURCES = test.iso8601.c diff --git a/tools/crm_failcount b/tools/crm_failcount index 94a8400..ed697e9 100755 --- a/tools/crm_failcount +++ b/tools/crm_failcount @@ -1,5 +1,6 @@ #!/bin/bash +resource="" options="" target=`crm_node -n` @@ -11,15 +12,7 @@ if [ $? != 0 ] ; then echo "crm_failcount - A convenience wrapper for crm_attrib # Note the quotes around `$TEMP': they are essential! eval set -- "$TEMP" -while true ; do - case "$1" in - -N|--node) target="$2"; shift; shift;; - -U|--uname) target="$2"; shift; shift;; - -v|--attr-value|-i|--attr-id) options="$options $1 $2"; shift; shift;; - -Q|--quiet|-D|--delete-attr|-G|--get-value|-V) options="$options $1"; shift;; - -r|--resource-id) options="$options -n fail-count-$2"; shift; shift;; - --version) crm_attribute --version; exit 0;; - --help) +function show_help() { echo "crm_failcount - A convenience wrapper for crm_attribute"; echo ""; echo "Set, update or remove the failcount for the specified resource on the named node"; @@ -43,10 +36,27 @@ while true ; do echo " -l, --lifetime=value Until when should the setting take affect." echo " Valid values: reboot, forever" echo " -i, --id=value (Advanced) The ID used to identify the attribute" +} + +while true ; do + case "$1" in + -N|--node) target="$2"; shift; shift;; + -U|--uname) target="$2"; shift; shift;; + -v|--attr-value|-i|--attr-id) options="$options $1 $2"; shift; shift;; + -Q|--quiet|-D|--delete-attr|-G|--get-value|-V) options="$options $1"; shift;; + -r|--resource-id) options="$options -n fail-count-$2"; resource="$2"; shift; shift;; + --version) crm_attribute --version; exit 0;; + --help) + show_help exit 0;; --) shift ; break ;; *) echo "Unknown option: $1. See --help for details." exit 1;; esac done +if [ "x$resource" = x ]; then + echo "You must supply a resource name to check. See 'crm_failcount --help' for details" + exit 1 +fi + crm_attribute -N $target $options -t status -d 0 diff --git a/tools/crm_resource.c b/tools/crm_resource.c index ff5effd..6e510e1 100644 --- a/tools/crm_resource.c +++ b/tools/crm_resource.c @@ -43,6 +43,9 @@ #include #include +#include "fake_transition.h" +extern xmlNode *do_calculations(pe_working_set_t * data_set, xmlNode * xml_input, crm_time_t * now); + bool scope_master = FALSE; gboolean do_force = FALSE; gboolean BE_QUIET = FALSE; @@ -1300,6 +1303,373 @@ generate_resource_params(resource_t * rsc, pe_working_set_t * data_set) return combined; } +static bool resource_is_running_on(resource_t *rsc, const char *host) +{ + bool found = TRUE; + GListPtr hIter = NULL; + GListPtr hosts = NULL; + + if(rsc == NULL) { + return FALSE; + } + + rsc->fns->location(rsc, &hosts, TRUE); + for (hIter = hosts; host != NULL && hIter != NULL; hIter = hIter->next) { + pe_node_t *node = (pe_node_t *) hIter->data; + + if(strcmp(host, node->details->uname) == 0) { + crm_trace("Resource %s is running on %s\n", rsc->id, host); + goto done; + } else if(strcmp(host, node->details->id) == 0) { + crm_trace("Resource %s is running on %s\n", rsc->id, host); + goto done; + } + } + + if(host != NULL) { + crm_trace("Resource %s is not running on: %s\n", rsc->id, host); + found = FALSE; + + } else if(host == NULL && hosts == NULL) { + crm_trace("Resource %s is not running\n", rsc->id); + found = FALSE; + } + + done: + + g_list_free(hosts); + return found; +} + +static GList *get_active_resources(const char *host, pe_working_set_t *data_set) +{ + GList *rIter = NULL; + GList *active = NULL; + + for (rIter = data_set->resources; rIter != NULL; rIter = rIter->next) { + resource_t *rsc = (resource_t *) rIter->data; + + if(resource_is_running_on(rsc, host)) { + active = g_list_append(active, strdup(rsc->id)); + } + } + + return active; +} + +static GList *subtract_lists(GList *from, GList *items) +{ + GList *item = NULL; + GList *result = g_list_copy(from); + + for (item = items; item != NULL; item = item->next) { + GList *candidate = NULL; + for (candidate = from; candidate != NULL; candidate = candidate->next) { + crm_info("Comparing %s with %s", candidate->data, item->data); + if(strcmp(candidate->data, item->data) == 0) { + result = g_list_remove(result, candidate->data); + break; + } + } + } + + return result; +} + +static void dump_list(GList *items, const char *tag) +{ + int lpc = 0; + GList *item = NULL; + + for (item = items; item != NULL; item = item->next) { + crm_trace("%s[%d]: %s", tag, lpc, item->data); + lpc++; + } +} + +static void display_list(GList *items, const char *tag) +{ + GList *item = NULL; + + for (item = items; item != NULL; item = item->next) { + fprintf(stdout, "%s%s\n", tag, (const char *)item->data); + } +} + +static int +update_dataset(cib_t *cib, pe_working_set_t * data_set, bool simulate) +{ + xmlNode *cib_xml_copy = NULL; + int rc = cib->cmds->query(cib, NULL, &cib_xml_copy, cib_scope_local | cib_sync_call); + + if(rc != pcmk_ok) { + fprintf(stdout, "Could not obtain the current CIB: %s (%d)\n", pcmk_strerror(rc), rc); + return crm_exit(rc); + + } else if (cli_config_update(&cib_xml_copy, NULL, FALSE) == FALSE) { + fprintf(stderr, "Could not upgrade the current CIB\n"); + return -ENOKEY; + } + + set_working_set_defaults(data_set); + data_set->input = cib_xml_copy; + data_set->now = crm_time_new(NULL); + + if(simulate) { + char *pid = crm_itoa(getpid()); + cib_t *shadow_cib = cib_shadow_new(pid); + char *shadow_file = get_shadow_file(pid); + + if (shadow_cib == NULL) { + fprintf(stderr, "Could not create shadow cib: '%s'\n", pid); + crm_exit(-ENXIO); + } + + rc = write_xml_file(cib_xml_copy, shadow_file, FALSE); + + if (rc < 0) { + fprintf(stderr, "Could not populate shadow cib: %s (%d)\n", pcmk_strerror(rc), rc); + free_xml(cib_xml_copy); + return rc; + } + + rc = shadow_cib->cmds->signon(shadow_cib, crm_system_name, cib_command); + if(rc != pcmk_ok) { + fprintf(stderr, "Could not connect to shadow cib: %s (%d)\n", pcmk_strerror(rc), rc); + free_xml(cib_xml_copy); + return rc; + } + + do_calculations(data_set, cib_xml_copy, NULL); + run_simulation(data_set, shadow_cib, NULL, TRUE); + rc = update_dataset(shadow_cib, data_set, FALSE); + + cib_delete(shadow_cib); + /* unlink(shadow_file); */ + free(shadow_file); + + } else { + cluster_status(data_set); + } + + return rc; +} + +static int +max_delay_in(pe_working_set_t * data_set, GList *resources) +{ + int max_delay = 0; + GList *item = NULL; + + for (item = resources; item != NULL; item = item->next) { + resource_t *rsc = pe_find_resource(data_set->resources, (const char *)item->data); + + if(rsc) { + char *key = g_strdup_printf("%s_%s_0", rsc->id, RSC_STOP); + action_t *stop = custom_action(rsc, key, RSC_STOP, NULL, TRUE, FALSE, data_set); + const char *value = g_hash_table_lookup(stop->meta, XML_ATTR_TIMEOUT); + int delay = crm_int_helper(value, NULL); + + if(delay > max_delay) { + crm_trace("Calculated new delay of %s ms due to %s", value, rsc->id); + max_delay = delay; + } + + pe_free_action(stop); + } + } + + + return 5 + (max_delay / 1000); +} + +static int +resource_restart(resource_t * rsc, const char *host, int timeout_ms, cib_t * cib) +{ + int rc = 0; + int lpc = 0; + int before = 0; + int step_timeout_s = 0; + int sleep_interval = 2; + int timeout = timeout_ms / 1000; + + bool is_clone = FALSE; + char *rsc_id = NULL; + + GList *list_delta = NULL; + GList *target_active = NULL; + GList *current_active = NULL; + GList *restart_target_active = NULL; + + pe_working_set_t data_set; + + if(resource_is_running_on(rsc, host) == FALSE) { + return -ENXIO; + } + + + rsc_id = strdup(rsc->id); + if(rsc->variant > pe_group) { + is_clone = TRUE; + } + + /* + grab full cib + determine resource state of list + disable or ban + poll and and watch for resources to get stopped + without --wait, calculate the stop timeout for each step and wait for that + if we hit --wait or the service timeout, re-enable or un-ban, report failure and indicate which resources we couldn't take down + if everything stopped, re-enable or un-ban + poll and and watch for resources to get stopped + without --wait, calculate the start timeout for each step and wait for that + if we hit --wait or the service timeout, report (different) failure and indicate which resources we couldn't bring back up + report success + + Optimizations: + - use constraints to determine ordered list of affected resources + - Allow a --no-deps option (aka. --force-restart) + */ + + + set_working_set_defaults(&data_set); + rc = update_dataset(cib, &data_set, FALSE); + if(rc != pcmk_ok) { + fprintf(stdout, "Could not get new resource list: %s (%d)\n", pcmk_strerror(rc), rc); + return rc; + } + + restart_target_active = get_active_resources(host, &data_set); + current_active = get_active_resources(host, &data_set); + + dump_list(current_active, "Origin"); + + if(is_clone && host) { + BE_QUIET = TRUE; + rc = ban_resource(rsc_id, host, NULL, cib); + + } else { + rc = set_resource_attr(rsc_id, NULL, NULL, XML_RSC_ATTR_TARGET_ROLE, RSC_STOPPED, FALSE, cib, &data_set); + } + if(rc != pcmk_ok) { + fprintf(stderr, "Could not set target-role for %s: %s (%d)\n", rsc_id, pcmk_strerror(rc), rc); + return crm_exit(rc); + } + + rc = update_dataset(cib, &data_set, TRUE); + if(rc != pcmk_ok) { + fprintf(stderr, "Could not determine which resources would be stopped\n"); + goto failure; + } + + target_active = get_active_resources(host, &data_set); + dump_list(target_active, "Target"); + + list_delta = subtract_lists(current_active, target_active); + fprintf(stdout, "Waiting for %d resources to stop:\n", g_list_length(list_delta)); + display_list(list_delta, " * "); + + step_timeout_s = timeout / sleep_interval; + while(g_list_length(list_delta) > 0) { + before = g_list_length(list_delta); + if(timeout_ms == 0) { + step_timeout_s = max_delay_in(&data_set, list_delta) / sleep_interval; + } + + /* We probably don't need the entire step timeout */ + for(lpc = 0; lpc < step_timeout_s && g_list_length(list_delta) > 0; lpc++) { + sleep(sleep_interval); + if(timeout) { + timeout -= sleep_interval; + crm_trace("%ds remaining", timeout); + } + rc = update_dataset(cib, &data_set, FALSE); + if(rc != pcmk_ok) { + fprintf(stderr, "Could not determine which resources were stopped\n"); + goto failure; + } + + current_active = get_active_resources(host, &data_set); + list_delta = subtract_lists(current_active, target_active); + dump_list(current_active, "Current"); + dump_list(list_delta, "Delta"); + } + + crm_trace("%d (was %d) resources remaining", before, g_list_length(list_delta)); + if(before == g_list_length(list_delta)) { + /* aborted during stop phase, print the contents of list_delta */ + fprintf(stderr, "Could not complete shutdown of %s, %d resources remaining\n", rsc_id, g_list_length(list_delta)); + display_list(list_delta, " * "); + rc = -ETIME; + goto failure; + } + + } + + if(is_clone && host) { + rc = clear_resource(rsc_id, host, NULL, cib); + + } else { + rc = delete_resource_attr(rsc_id, NULL, NULL, XML_RSC_ATTR_TARGET_ROLE, cib, &data_set); + } + + if(rc != pcmk_ok) { + fprintf(stderr, "Could not unset target-role for %s: %s (%d)\n", rsc_id, pcmk_strerror(rc), rc); + return crm_exit(rc); + } + + target_active = restart_target_active; + list_delta = subtract_lists(target_active, current_active); + fprintf(stdout, "Waiting for %d resources to start again:\n", g_list_length(list_delta)); + display_list(list_delta, " * "); + + step_timeout_s = timeout / sleep_interval; + while(g_list_length(list_delta) > 0) { + if(timeout_ms == 0) { + step_timeout_s = max_delay_in(&data_set, list_delta) / sleep_interval; + } + + /* We probably don't need the entire step timeout */ + for(lpc = 0; lpc < step_timeout_s && g_list_length(list_delta) > 0; lpc++) { + sleep(sleep_interval); + if(timeout) { + timeout -= sleep_interval; + crm_trace("%ds remaining", timeout); + } + + rc = update_dataset(cib, &data_set, FALSE); + if(rc != pcmk_ok) { + fprintf(stderr, "Could not determine which resources were started\n"); + goto failure; + } + + current_active = get_active_resources(host, &data_set); + list_delta = subtract_lists(target_active, current_active); + dump_list(current_active, "Current"); + dump_list(list_delta, "Delta"); + } + + if(before == g_list_length(list_delta)) { + /* aborted during start phase, print the contents of list_delta */ + fprintf(stdout, "Could not complete restart of %s, %d resources remaining\n", rsc_id, g_list_length(list_delta)); + display_list(list_delta, " * "); + rc = -ETIME; + goto failure; + } + + } while(g_list_length(list_delta) > 0); + + return pcmk_ok; + + failure: + if(is_clone && host) { + clear_resource(rsc_id, host, NULL, cib); + + } else { + delete_resource_attr(rsc_id, NULL, NULL, XML_RSC_ATTR_TARGET_ROLE, cib, &data_set); + } + return rc; +} /* *INDENT-OFF* */ static struct crm_option long_options[] = { @@ -1371,6 +1741,7 @@ static struct crm_option long_options[] = { {"-spacer-", 1, 0, '-', "\nAdvanced Commands:"}, {"delete", 0, 0, 'D', "\t\t(Advanced) Delete a resource from the CIB"}, {"fail", 0, 0, 'F', "\t\t(Advanced) Tell the cluster this resource has failed"}, + {"restart", 0, 0, 0, NULL, 1}, {"force-stop", 0, 0, 0, "\t(Advanced) Bypass the cluster and stop a resource on the local node. Additional detail with -V"}, {"force-start",0, 0, 0, "\t(Advanced) Bypass the cluster and start a resource on the local node. Additional detail with -V"}, {"force-check",0, 0, 0, "\t(Advanced) Bypass the cluster and check the state of a resource on the local node. Additional detail with -V\n"}, @@ -1384,6 +1755,7 @@ static struct crm_option long_options[] = { {"utilization", 0, 0, 'z', "\tModify a resource's utilization attribute. For use with -p, -g, -d"}, {"set-name", 1, 0, 's', "\t(Advanced) ID of the instance_attributes object to change"}, {"nvpair", 1, 0, 'i', "\t(Advanced) ID of the nvpair object to change/delete"}, + {"timeout", 1, 0, 'T', "\t(Advanced) How long to wait for --restart to take effect", 1}, {"force", 0, 0, 'f', "\n" /* Is this actually true anymore? "\t\tForce the resource to move by creating a rule for the current location and a score of -INFINITY" "\n\t\tThis should be used if the resource's stickiness and constraint scores total more than INFINITY (Currently 100,000)" @@ -1444,6 +1816,7 @@ main(int argc, char **argv) int rc = pcmk_ok; int option_index = 0; + int timeout_ms = 0; int argerr = 0; int flag; @@ -1469,6 +1842,7 @@ main(int argc, char **argv) recursive = TRUE; } else if (safe_str_eq("force-stop", longname) + || safe_str_eq("restart", longname) || safe_str_eq("force-start", longname) || safe_str_eq("force-check", longname)) { rsc_cmd = flag; @@ -1618,6 +1992,9 @@ main(int argc, char **argv) case 't': rsc_type = optarg; break; + case 'T': + timeout_ms = crm_get_msec(optarg); + break; case 'C': case 'R': case 'P': @@ -1769,6 +2146,11 @@ main(int argc, char **argv) goto bail; } + } else if (rsc_cmd == 0 && rsc_long_cmd && safe_str_eq(rsc_long_cmd, "restart")) { + resource_t *rsc = pe_find_resource(data_set.resources, rsc_id); + + rc = resource_restart(rsc, host_uname, timeout_ms, cib_conn); + } else if (rsc_cmd == 0 && rsc_long_cmd) { svc_action_t *op = NULL; const char *rtype = NULL; @@ -1801,6 +2183,16 @@ main(int argc, char **argv) action = "monitor"; } + if(rsc->variant == pe_clone || rsc->variant == pe_master) { + /* Grab the first child resource in the hope its not a group */ + rsc = rsc->children->data; + } + + if(rsc->variant == pe_group) { + CMD_ERR("Sorry, --%s doesn't support group resources\n", rsc_long_cmd); + crm_exit(EOPNOTSUPP); + } + rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); rprov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE); diff --git a/tools/crm_simulate.c b/tools/crm_simulate.c index 7c0dcc7..d4e2238 100644 --- a/tools/crm_simulate.c +++ b/tools/crm_simulate.c @@ -34,19 +34,14 @@ #include #include #include +#include "fake_transition.h" cib_t *global_cib = NULL; GListPtr op_fail = NULL; gboolean quiet = FALSE; -gboolean bringing_nodes_online = FALSE; gboolean print_pending = FALSE; char *temp_shadow = NULL; - -#define new_node_template "//"XML_CIB_TAG_NODE"[@uname='%s']" -#define node_template "//"XML_CIB_TAG_STATE"[@uname='%s']" -#define rsc_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']" -#define op_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']/"XML_LRM_TAG_RSC_OP"[@id='%s']" -/* #define op_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']/"XML_LRM_TAG_RSC_OP"[@id='%s' and @"XML_LRM_ATTR_CALLID"='%d']" */ +extern gboolean bringing_nodes_online; #define quiet_log(fmt, args...) do { \ if(quiet == FALSE) { \ @@ -68,472 +63,6 @@ get_date(void) return NULL; } -static xmlNode * -find_resource(xmlNode * cib_node, const char *resource) -{ - char *xpath = NULL; - xmlNode *match = NULL; - const char *node = crm_element_value(cib_node, XML_ATTR_UNAME); - int max = strlen(rsc_template) + strlen(resource) + strlen(node) + 1; - - xpath = calloc(1, max); - - snprintf(xpath, max, rsc_template, node, resource); - match = get_xpath_object(xpath, cib_node, LOG_DEBUG_2); - - free(xpath); - return match; -} - -static void -create_node_entry(cib_t * cib_conn, const char *node) -{ - int rc = pcmk_ok; - int max = strlen(new_node_template) + strlen(node) + 1; - char *xpath = NULL; - - xpath = calloc(1, max); - - snprintf(xpath, max, new_node_template, node); - rc = cib_conn->cmds->query(cib_conn, xpath, NULL, cib_xpath | cib_sync_call | cib_scope_local); - - if (rc == -ENXIO) { - xmlNode *cib_object = create_xml_node(NULL, XML_CIB_TAG_NODE); - - /* Using node uname as uuid ala corosync/openais */ - crm_xml_add(cib_object, XML_ATTR_ID, node); - crm_xml_add(cib_object, XML_ATTR_UNAME, node); - cib_conn->cmds->create(cib_conn, XML_CIB_TAG_NODES, cib_object, - cib_sync_call | cib_scope_local); - /* Not bothering with subsequent query to see if it exists, - we'll bomb out later in the call to query_node_uuid()... */ - - free_xml(cib_object); - } - - free(xpath); -} - -static xmlNode * -inject_node_state(cib_t * cib_conn, const char *node, const char *uuid) -{ - int rc = pcmk_ok; - int max = strlen(rsc_template) + strlen(node) + 1; - char *xpath = NULL; - xmlNode *cib_object = NULL; - - xpath = calloc(1, max); - - if (bringing_nodes_online) { - create_node_entry(cib_conn, node); - } - - snprintf(xpath, max, node_template, node); - rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object, - cib_xpath | cib_sync_call | cib_scope_local); - - if (cib_object && ID(cib_object) == NULL) { - crm_err("Detected multiple node_state entries for xpath=%s, bailing", xpath); - crm_log_xml_warn(cib_object, "Duplicates"); - crm_exit(ENOTUNIQ); - } - - if (rc == -ENXIO) { - char *found_uuid = NULL; - - if (uuid == NULL) { - query_node_uuid(cib_conn, node, &found_uuid, NULL); - } else { - found_uuid = strdup(uuid); - } - - cib_object = create_xml_node(NULL, XML_CIB_TAG_STATE); - crm_xml_add(cib_object, XML_ATTR_UUID, found_uuid); - crm_xml_add(cib_object, XML_ATTR_UNAME, node); - cib_conn->cmds->create(cib_conn, XML_CIB_TAG_STATUS, cib_object, - cib_sync_call | cib_scope_local); - free_xml(cib_object); - free(found_uuid); - - rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object, - cib_xpath | cib_sync_call | cib_scope_local); - crm_trace("injecting node state for %s. rc is %d", node, rc); - } - - free(xpath); - CRM_ASSERT(rc == pcmk_ok); - return cib_object; -} - -static xmlNode * -modify_node(cib_t * cib_conn, char *node, gboolean up) -{ - xmlNode *cib_node = inject_node_state(cib_conn, node, NULL); - - if (up) { - crm_xml_add(cib_node, XML_NODE_IN_CLUSTER, XML_BOOLEAN_YES); - crm_xml_add(cib_node, XML_NODE_IS_PEER, ONLINESTATUS); - crm_xml_add(cib_node, XML_NODE_JOIN_STATE, CRMD_JOINSTATE_MEMBER); - crm_xml_add(cib_node, XML_NODE_EXPECTED, CRMD_JOINSTATE_MEMBER); - - } else { - crm_xml_add(cib_node, XML_NODE_IN_CLUSTER, XML_BOOLEAN_NO); - crm_xml_add(cib_node, XML_NODE_IS_PEER, OFFLINESTATUS); - crm_xml_add(cib_node, XML_NODE_JOIN_STATE, CRMD_JOINSTATE_DOWN); - crm_xml_add(cib_node, XML_NODE_EXPECTED, CRMD_JOINSTATE_DOWN); - } - - crm_xml_add(cib_node, XML_ATTR_ORIGIN, crm_system_name); - return cib_node; -} - -static void -inject_transient_attr(xmlNode * cib_node, const char *name, const char *value) -{ - xmlNode *attrs = NULL; - xmlNode *container = NULL; - xmlNode *nvp = NULL; - const char *node_uuid = ID(cib_node); - char *nvp_id = crm_concat(name, node_uuid, '-'); - - crm_info("Injecting attribute %s=%s into %s '%s'", name, value, xmlGetNodePath(cib_node), - ID(cib_node)); - - attrs = first_named_child(cib_node, XML_TAG_TRANSIENT_NODEATTRS); - if (attrs == NULL) { - attrs = create_xml_node(cib_node, XML_TAG_TRANSIENT_NODEATTRS); - crm_xml_add(attrs, XML_ATTR_ID, node_uuid); - } - - container = first_named_child(attrs, XML_TAG_ATTR_SETS); - if (container == NULL) { - container = create_xml_node(attrs, XML_TAG_ATTR_SETS); - crm_xml_add(container, XML_ATTR_ID, node_uuid); - } - - nvp = create_xml_node(container, XML_CIB_TAG_NVPAIR); - crm_xml_add(nvp, XML_ATTR_ID, nvp_id); - crm_xml_add(nvp, XML_NVPAIR_ATTR_NAME, name); - crm_xml_add(nvp, XML_NVPAIR_ATTR_VALUE, value); - - free(nvp_id); -} - -static xmlNode * -inject_resource(xmlNode * cib_node, const char *resource, const char *rclass, const char *rtype, - const char *rprovider) -{ - xmlNode *lrm = NULL; - xmlNode *container = NULL; - xmlNode *cib_resource = NULL; - char *xpath = NULL; - - cib_resource = find_resource(cib_node, resource); - if (cib_resource != NULL) { - return cib_resource; - } - - /* One day, add query for class, provider, type */ - - if (rclass == NULL || rtype == NULL) { - fprintf(stderr, "Resource %s not found in the status section of %s." - " Please supply the class and type to continue\n", resource, ID(cib_node)); - return NULL; - - } else if (safe_str_neq(rclass, "ocf") - && safe_str_neq(rclass, "stonith") - && safe_str_neq(rclass, "heartbeat") - && safe_str_neq(rclass, "service") - && safe_str_neq(rclass, "upstart") - && safe_str_neq(rclass, "systemd") - && safe_str_neq(rclass, "lsb")) { - fprintf(stderr, "Invalid class for %s: %s\n", resource, rclass); - return NULL; - - } else if (safe_str_eq(rclass, "ocf") && rprovider == NULL) { - fprintf(stderr, "Please specify the provider for resource %s\n", resource); - return NULL; - } - - xpath = (char *)xmlGetNodePath(cib_node); - crm_info("Injecting new resource %s into %s '%s'", resource, xpath, ID(cib_node)); - free(xpath); - - lrm = first_named_child(cib_node, XML_CIB_TAG_LRM); - if (lrm == NULL) { - const char *node_uuid = ID(cib_node); - - lrm = create_xml_node(cib_node, XML_CIB_TAG_LRM); - crm_xml_add(lrm, XML_ATTR_ID, node_uuid); - } - - container = first_named_child(lrm, XML_LRM_TAG_RESOURCES); - if (container == NULL) { - container = create_xml_node(lrm, XML_LRM_TAG_RESOURCES); - } - - cib_resource = create_xml_node(container, XML_LRM_TAG_RESOURCE); - crm_xml_add(cib_resource, XML_ATTR_ID, resource); - - crm_xml_add(cib_resource, XML_AGENT_ATTR_CLASS, rclass); - crm_xml_add(cib_resource, XML_AGENT_ATTR_PROVIDER, rprovider); - crm_xml_add(cib_resource, XML_ATTR_TYPE, rtype); - - return cib_resource; -} - -static lrmd_event_data_t * -create_op(xmlNode * cib_resource, const char *task, int interval, int outcome) -{ - lrmd_event_data_t *op = NULL; - xmlNode *xop = NULL; - - op = calloc(1, sizeof(lrmd_event_data_t)); - - op->rsc_id = strdup(ID(cib_resource)); - op->interval = interval; - op->op_type = strdup(task); - - op->rc = outcome; - op->op_status = 0; - op->params = NULL; /* TODO: Fill me in */ - op->t_run = time(NULL); - op->t_rcchange = op->t_run; - - op->call_id = 0; - for (xop = __xml_first_child(cib_resource); xop != NULL; xop = __xml_next(xop)) { - int tmp = 0; - - crm_element_value_int(xop, XML_LRM_ATTR_CALLID, &tmp); - if (tmp > op->call_id) { - op->call_id = tmp; - } - } - op->call_id++; - - return op; -} - -static xmlNode * -inject_op(xmlNode * cib_resource, lrmd_event_data_t * op, int target_rc) -{ - return create_operation_update(cib_resource, op, CRM_FEATURE_SET, target_rc, crm_system_name, - LOG_DEBUG_2); -} - -static void -update_failcounts(xmlNode * cib_node, const char *resource, int interval, int rc) -{ - if (rc == 0) { - return; - - } else if (rc == 7 && interval == 0) { - return; - - } else { - char *name = NULL; - char *now = crm_itoa(time(NULL)); - - name = crm_concat("fail-count", resource, '-'); - inject_transient_attr(cib_node, name, "value++"); - - name = crm_concat("last-failure", resource, '-'); - inject_transient_attr(cib_node, name, now); - - free(name); - free(now); - } -} - -static gboolean -exec_pseudo_action(crm_graph_t * graph, crm_action_t * action) -{ - const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); - const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); - - action->confirmed = TRUE; - - quiet_log(" * Pseudo action: %s%s%s\n", task, node ? " on " : "", node ? node : ""); - update_graph(graph, action); - return TRUE; -} - -GListPtr resource_list = NULL; - -static gboolean -exec_rsc_action(crm_graph_t * graph, crm_action_t * action) -{ - int rc = 0; - GListPtr gIter = NULL; - lrmd_event_data_t *op = NULL; - int target_outcome = 0; - gboolean uname_is_uuid = FALSE; - - const char *rtype = NULL; - const char *rclass = NULL; - const char *resource = NULL; - const char *rprovider = NULL; - const char *operation = crm_element_value(action->xml, "operation"); - const char *target_rc_s = crm_meta_value(action->params, XML_ATTR_TE_TARGET_RC); - - xmlNode *cib_node = NULL; - xmlNode *cib_resource = NULL; - xmlNode *action_rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE); - - char *node = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET); - char *uuid = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET_UUID); - const char *router_node = crm_element_value(action->xml, XML_LRM_ATTR_ROUTER_NODE); - - if (safe_str_eq(operation, CRM_OP_PROBED) - || safe_str_eq(operation, CRM_OP_REPROBE)) { - crm_info("Skipping %s op for %s\n", operation, node); - goto done; - } - - if (action_rsc == NULL) { - crm_log_xml_err(action->xml, "Bad"); - free(node); free(uuid); - return FALSE; - } - - /* Look for the preferred name - * If not found, try the expected 'local' name - * If not found use the preferred name anyway - */ - resource = crm_element_value(action_rsc, XML_ATTR_ID); - if (pe_find_resource(resource_list, resource) == NULL) { - const char *longname = crm_element_value(action_rsc, XML_ATTR_ID_LONG); - - if (pe_find_resource(resource_list, longname)) { - resource = longname; - } - } - - if (safe_str_eq(operation, "delete")) { - quiet_log(" * Resource action: %-15s delete on %s\n", resource, node); - goto done; - } - - rclass = crm_element_value(action_rsc, XML_AGENT_ATTR_CLASS); - rtype = crm_element_value(action_rsc, XML_ATTR_TYPE); - rprovider = crm_element_value(action_rsc, XML_AGENT_ATTR_PROVIDER); - - if (target_rc_s != NULL) { - target_outcome = crm_parse_int(target_rc_s, "0"); - } - - CRM_ASSERT(global_cib->cmds->query(global_cib, NULL, NULL, cib_sync_call | cib_scope_local) == - pcmk_ok); - - if (router_node) { - uname_is_uuid = TRUE; - } - - cib_node = inject_node_state(global_cib, node, uname_is_uuid ? node : uuid); - CRM_ASSERT(cib_node != NULL); - - cib_resource = inject_resource(cib_node, resource, rclass, rtype, rprovider); - CRM_ASSERT(cib_resource != NULL); - - op = convert_graph_action(cib_resource, action, 0, target_outcome); - if (op->interval) { - quiet_log(" * Resource action: %-15s %s=%d on %s\n", resource, op->op_type, op->interval, - node); - } else { - quiet_log(" * Resource action: %-15s %s on %s\n", resource, op->op_type, node); - } - - for (gIter = op_fail; gIter != NULL; gIter = gIter->next) { - char *spec = (char *)gIter->data; - char *key = NULL; - - key = calloc(1, 1 + strlen(spec)); - snprintf(key, strlen(spec), "%s_%s_%d@%s=", resource, op->op_type, op->interval, node); - - if (strncasecmp(key, spec, strlen(key)) == 0) { - sscanf(spec, "%*[^=]=%d", (int *)&op->rc); - - action->failed = TRUE; - graph->abort_priority = INFINITY; - printf("\tPretending action %d failed with rc=%d\n", action->id, op->rc); - update_failcounts(cib_node, resource, op->interval, op->rc); - free(key); - break; - } - free(key); - } - - inject_op(cib_resource, op, target_outcome); - lrmd_free_event(op); - - rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, - cib_sync_call | cib_scope_local); - CRM_ASSERT(rc == pcmk_ok); - - done: - free(node); free(uuid); - free_xml(cib_node); - action->confirmed = TRUE; - update_graph(graph, action); - return TRUE; -} - -static gboolean -exec_crmd_action(crm_graph_t * graph, crm_action_t * action) -{ - const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); - const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); - xmlNode *rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE); - - action->confirmed = TRUE; - - if(rsc) { - quiet_log(" * Cluster action: %s for %s on %s\n", task, ID(rsc), node); - } else { - quiet_log(" * Cluster action: %s on %s\n", task, node); - } - update_graph(graph, action); - return TRUE; -} - -#define STATUS_PATH_MAX 512 -static gboolean -exec_stonith_action(crm_graph_t * graph, crm_action_t * action) -{ - const char *op = crm_meta_value(action->params, "stonith_action"); - char *target = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET); - - quiet_log(" * Fencing %s (%s)\n", target, op); - if(safe_str_neq(op, "on")) { - int rc = 0; - char xpath[STATUS_PATH_MAX]; - xmlNode *cib_node = modify_node(global_cib, target, FALSE); - - crm_xml_add(cib_node, XML_ATTR_ORIGIN, __FUNCTION__); - CRM_ASSERT(cib_node != NULL); - - rc = global_cib->cmds->replace(global_cib, XML_CIB_TAG_STATUS, cib_node, - cib_sync_call | cib_scope_local); - CRM_ASSERT(rc == pcmk_ok); - - snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", target, XML_CIB_TAG_LRM); - global_cib->cmds->delete(global_cib, xpath, NULL, - cib_xpath | cib_sync_call | cib_scope_local); - - snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", target, - XML_TAG_TRANSIENT_NODEATTRS); - global_cib->cmds->delete(global_cib, xpath, NULL, - cib_xpath | cib_sync_call | cib_scope_local); - - free_xml(cib_node); - } - - action->confirmed = TRUE; - update_graph(graph, action); - free(target); - return TRUE; -} - static void print_cluster_status(pe_working_set_t * data_set, long options) { @@ -657,62 +186,6 @@ print_cluster_status(pe_working_set_t * data_set, long options) fprintf(stdout, "\n"); } -static int -run_simulation(pe_working_set_t * data_set) -{ - crm_graph_t *transition = NULL; - enum transition_status graph_rc = -1; - - crm_graph_functions_t exec_fns = { - exec_pseudo_action, - exec_rsc_action, - exec_crmd_action, - exec_stonith_action, - }; - - set_graph_functions(&exec_fns); - - quiet_log("\nExecuting cluster transition:\n"); - transition = unpack_graph(data_set->graph, crm_system_name); - print_graph(LOG_DEBUG, transition); - - resource_list = data_set->resources; - do { - graph_rc = run_graph(transition); - - } while (graph_rc == transition_active); - resource_list = NULL; - - if (graph_rc != transition_complete) { - fprintf(stdout, "Transition failed: %s\n", transition_status(graph_rc)); - print_graph(LOG_ERR, transition); - } - destroy_graph(transition); - if (graph_rc != transition_complete) { - fprintf(stdout, "An invalid transition was produced\n"); - } - - if (quiet == FALSE) { - xmlNode *cib_object = NULL; - int rc = - global_cib->cmds->query(global_cib, NULL, &cib_object, cib_sync_call | cib_scope_local); - - CRM_ASSERT(rc == pcmk_ok); - quiet_log("\nRevised cluster status:\n"); - cleanup_alloc_calculations(data_set); - data_set->input = cib_object; - data_set->now = get_date(); - - cluster_status(data_set); - print_cluster_status(data_set, 0); - } - - if (graph_rc != transition_complete) { - return graph_rc; - } - return 0; -} - static char * create_action_name(action_t * action) { @@ -883,274 +356,6 @@ create_dotfile(pe_working_set_t * data_set, const char *dot_file, gboolean all_a } } -static int -find_ticket_state(cib_t * the_cib, const char *ticket_id, xmlNode ** ticket_state_xml) -{ - int offset = 0; - static int xpath_max = 1024; - int rc = pcmk_ok; - xmlNode *xml_search = NULL; - - char *xpath_string = NULL; - - CRM_ASSERT(ticket_state_xml != NULL); - *ticket_state_xml = NULL; - - xpath_string = calloc(1, xpath_max); - offset += snprintf(xpath_string + offset, xpath_max - offset, "%s", "/cib/status/tickets"); - - if (ticket_id) { - offset += snprintf(xpath_string + offset, xpath_max - offset, "/%s[@id=\"%s\"]", - XML_CIB_TAG_TICKET_STATE, ticket_id); - } - CRM_LOG_ASSERT(offset > 0); - rc = the_cib->cmds->query(the_cib, xpath_string, &xml_search, - cib_sync_call | cib_scope_local | cib_xpath); - - if (rc != pcmk_ok) { - goto bail; - } - - crm_log_xml_debug(xml_search, "Match"); - if (xml_has_children(xml_search)) { - if (ticket_id) { - fprintf(stdout, "Multiple ticket_states match ticket_id=%s\n", ticket_id); - } - *ticket_state_xml = xml_search; - } else { - *ticket_state_xml = xml_search; - } - - bail: - free(xpath_string); - return rc; -} - -static int -set_ticket_state_attr(const char *ticket_id, const char *attr_name, - const char *attr_value, cib_t * cib, int cib_options) -{ - int rc = pcmk_ok; - xmlNode *xml_top = NULL; - xmlNode *ticket_state_xml = NULL; - - rc = find_ticket_state(cib, ticket_id, &ticket_state_xml); - if (rc == pcmk_ok) { - crm_debug("Found a match state for ticket: id=%s", ticket_id); - xml_top = ticket_state_xml; - - } else if (rc != -ENXIO) { - return rc; - - } else { - xmlNode *xml_obj = NULL; - - xml_top = create_xml_node(NULL, XML_CIB_TAG_STATUS); - xml_obj = create_xml_node(xml_top, XML_CIB_TAG_TICKETS); - ticket_state_xml = create_xml_node(xml_obj, XML_CIB_TAG_TICKET_STATE); - crm_xml_add(ticket_state_xml, XML_ATTR_ID, ticket_id); - } - - crm_xml_add(ticket_state_xml, attr_name, attr_value); - - crm_log_xml_debug(xml_top, "Update"); - - rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, xml_top, cib_options); - - free_xml(xml_top); - - return rc; -} - -static void -modify_configuration(pe_working_set_t * data_set, - 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 rc = pcmk_ok; - GListPtr gIter = NULL; - - xmlNode *cib_op = NULL; - xmlNode *cib_node = NULL; - xmlNode *cib_resource = NULL; - - lrmd_event_data_t *op = NULL; - - if (quorum) { - xmlNode *top = create_xml_node(NULL, XML_TAG_CIB); - - quiet_log(" + Setting quorum: %s\n", quorum); - /* crm_xml_add(top, XML_ATTR_DC_UUID, dc_uuid); */ - crm_xml_add(top, XML_ATTR_HAVE_QUORUM, quorum); - - rc = global_cib->cmds->modify(global_cib, NULL, top, cib_sync_call | cib_scope_local); - CRM_ASSERT(rc == pcmk_ok); - } - - if (watchdog) { - quiet_log(" + Setting watchdog: %s\n", watchdog); - - rc = update_attr_delegate(global_cib, cib_sync_call | cib_scope_local, - XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL, NULL, - XML_ATTR_HAVE_WATCHDOG, watchdog, FALSE, NULL, NULL); - - CRM_ASSERT(rc == pcmk_ok); - } - - for (gIter = node_up; gIter != NULL; gIter = gIter->next) { - char *node = (char *)gIter->data; - - quiet_log(" + Bringing node %s online\n", node); - cib_node = modify_node(global_cib, node, TRUE); - CRM_ASSERT(cib_node != NULL); - - rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, - cib_sync_call | cib_scope_local); - CRM_ASSERT(rc == pcmk_ok); - free_xml(cib_node); - } - - for (gIter = node_down; gIter != NULL; gIter = gIter->next) { - char xpath[STATUS_PATH_MAX]; - char *node = (char *)gIter->data; - - quiet_log(" + Taking node %s offline\n", node); - cib_node = modify_node(global_cib, node, FALSE); - CRM_ASSERT(cib_node != NULL); - - rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, - cib_sync_call | cib_scope_local); - CRM_ASSERT(rc == pcmk_ok); - free_xml(cib_node); - - snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", node, XML_CIB_TAG_LRM); - global_cib->cmds->delete(global_cib, xpath, NULL, - cib_xpath | cib_sync_call | cib_scope_local); - - snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", node, - XML_TAG_TRANSIENT_NODEATTRS); - global_cib->cmds->delete(global_cib, xpath, NULL, - cib_xpath | cib_sync_call | cib_scope_local); - - } - - for (gIter = node_fail; gIter != NULL; gIter = gIter->next) { - char *node = (char *)gIter->data; - - quiet_log(" + Failing node %s\n", node); - cib_node = modify_node(global_cib, node, TRUE); - crm_xml_add(cib_node, XML_NODE_IN_CLUSTER, XML_BOOLEAN_NO); - CRM_ASSERT(cib_node != NULL); - - rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, - cib_sync_call | cib_scope_local); - CRM_ASSERT(rc == pcmk_ok); - free_xml(cib_node); - } - - for (gIter = ticket_grant; gIter != NULL; gIter = gIter->next) { - char *ticket_id = (char *)gIter->data; - - quiet_log(" + Granting ticket %s\n", ticket_id); - rc = set_ticket_state_attr(ticket_id, "granted", "true", - global_cib, cib_sync_call | cib_scope_local); - - CRM_ASSERT(rc == pcmk_ok); - } - - for (gIter = ticket_revoke; gIter != NULL; gIter = gIter->next) { - char *ticket_id = (char *)gIter->data; - - quiet_log(" + Revoking ticket %s\n", ticket_id); - rc = set_ticket_state_attr(ticket_id, "granted", "false", - global_cib, cib_sync_call | cib_scope_local); - - CRM_ASSERT(rc == pcmk_ok); - } - - for (gIter = ticket_standby; gIter != NULL; gIter = gIter->next) { - char *ticket_id = (char *)gIter->data; - - quiet_log(" + Making ticket %s standby\n", ticket_id); - rc = set_ticket_state_attr(ticket_id, "standby", "true", - global_cib, cib_sync_call | cib_scope_local); - - CRM_ASSERT(rc == pcmk_ok); - } - - for (gIter = ticket_activate; gIter != NULL; gIter = gIter->next) { - char *ticket_id = (char *)gIter->data; - - quiet_log(" + Activating ticket %s\n", ticket_id); - rc = set_ticket_state_attr(ticket_id, "standby", "false", - global_cib, cib_sync_call | cib_scope_local); - - CRM_ASSERT(rc == pcmk_ok); - } - - for (gIter = op_inject; gIter != NULL; gIter = gIter->next) { - char *spec = (char *)gIter->data; - - int rc = 0; - int outcome = 0; - int interval = 0; - - char *key = NULL; - char *node = NULL; - char *task = NULL; - char *resource = NULL; - - const char *rtype = NULL; - const char *rclass = NULL; - const char *rprovider = NULL; - - resource_t *rsc = NULL; - - quiet_log(" + Injecting %s into the configuration\n", spec); - - key = calloc(1, strlen(spec) + 1); - node = calloc(1, strlen(spec) + 1); - rc = sscanf(spec, "%[^@]@%[^=]=%d", key, node, &outcome); - CRM_CHECK(rc == 3, - fprintf(stderr, "Invalid operation spec: %s. Only found %d fields\n", spec, rc); - continue); - - parse_op_key(key, &resource, &task, &interval); - - rsc = pe_find_resource(data_set->resources, resource); - if (rsc == NULL) { - fprintf(stderr, " - Invalid resource name: %s\n", resource); - } else { - rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); - rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE); - rprovider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); - - cib_node = inject_node_state(global_cib, node, NULL); - CRM_ASSERT(cib_node != NULL); - - update_failcounts(cib_node, resource, interval, outcome); - - cib_resource = inject_resource(cib_node, resource, rclass, rtype, rprovider); - CRM_ASSERT(cib_resource != NULL); - - op = create_op(cib_resource, task, interval, outcome); - CRM_ASSERT(op != NULL); - - cib_op = inject_op(cib_resource, op, 0); - CRM_ASSERT(cib_op != NULL); - lrmd_free_event(op); - - rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, - cib_sync_call | cib_scope_local); - CRM_ASSERT(rc == pcmk_ok); - } - free(task); - free(node); - free(key); - } -} - static void setup_input(const char *input, const char *output) { @@ -1571,7 +776,7 @@ main(int argc, char **argv) if (modified) { quiet_log("Performing requested modifications\n"); - modify_configuration(&data_set, quorum, watchdog, node_up, node_down, node_fail, op_inject, + modify_configuration(&data_set, global_cib, quorum, watchdog, node_up, node_down, node_fail, op_inject, ticket_grant, ticket_revoke, ticket_standby, ticket_activate); rc = global_cib->cmds->query(global_cib, NULL, &input, cib_sync_call); @@ -1632,7 +837,14 @@ main(int argc, char **argv) } if (simulate) { - rc = run_simulation(&data_set); + rc = run_simulation(&data_set, global_cib, op_fail, quiet); + if(quiet == FALSE) { + data_set.now = get_date(); + + quiet_log("\nRevised cluster status:\n"); + cluster_status(&data_set); + print_cluster_status(&data_set, 0); + } } done: diff --git a/tools/fake_transition.c b/tools/fake_transition.c new file mode 100644 index 0000000..d6d71eb --- /dev/null +++ b/tools/fake_transition.c @@ -0,0 +1,846 @@ +/* + * Copyright (C) 2009 Andrew Beekhof + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 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 + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "fake_transition.h" + +static bool fake_quiet = FALSE; +static cib_t *fake_cib = NULL; +static GListPtr fake_resource_list = NULL; +static GListPtr fake_op_fail_list = NULL; +gboolean bringing_nodes_online = FALSE; + +#define STATUS_PATH_MAX 512 + +#define quiet_log(fmt, args...) do { \ + if(fake_quiet) { \ + crm_trace(fmt, ##args); \ + } else { \ + printf(fmt , ##args); \ + } \ + } while(0) + +#define new_node_template "//"XML_CIB_TAG_NODE"[@uname='%s']" +#define node_template "//"XML_CIB_TAG_STATE"[@uname='%s']" +#define rsc_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']" +#define op_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']/"XML_LRM_TAG_RSC_OP"[@id='%s']" +/* #define op_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']/"XML_LRM_TAG_RSC_OP"[@id='%s' and @"XML_LRM_ATTR_CALLID"='%d']" */ + + +static void +inject_transient_attr(xmlNode * cib_node, const char *name, const char *value) +{ + xmlNode *attrs = NULL; + xmlNode *container = NULL; + xmlNode *nvp = NULL; + const char *node_uuid = ID(cib_node); + char *nvp_id = crm_concat(name, node_uuid, '-'); + + quiet_log("Injecting attribute %s=%s into %s '%s'", name, value, xmlGetNodePath(cib_node), + ID(cib_node)); + + attrs = first_named_child(cib_node, XML_TAG_TRANSIENT_NODEATTRS); + if (attrs == NULL) { + attrs = create_xml_node(cib_node, XML_TAG_TRANSIENT_NODEATTRS); + crm_xml_add(attrs, XML_ATTR_ID, node_uuid); + } + + container = first_named_child(attrs, XML_TAG_ATTR_SETS); + if (container == NULL) { + container = create_xml_node(attrs, XML_TAG_ATTR_SETS); + crm_xml_add(container, XML_ATTR_ID, node_uuid); + } + + nvp = create_xml_node(container, XML_CIB_TAG_NVPAIR); + crm_xml_add(nvp, XML_ATTR_ID, nvp_id); + crm_xml_add(nvp, XML_NVPAIR_ATTR_NAME, name); + crm_xml_add(nvp, XML_NVPAIR_ATTR_VALUE, value); + + free(nvp_id); +} + +static void +update_failcounts(xmlNode * cib_node, const char *resource, int interval, int rc) +{ + if (rc == 0) { + return; + + } else if (rc == 7 && interval == 0) { + return; + + } else { + char *name = NULL; + char *now = crm_itoa(time(NULL)); + + name = crm_concat("fail-count", resource, '-'); + inject_transient_attr(cib_node, name, "value++"); + + name = crm_concat("last-failure", resource, '-'); + inject_transient_attr(cib_node, name, now); + + free(name); + free(now); + } +} + +static void +create_node_entry(cib_t * cib_conn, const char *node) +{ + int rc = pcmk_ok; + int max = strlen(new_node_template) + strlen(node) + 1; + char *xpath = NULL; + + xpath = calloc(1, max); + + snprintf(xpath, max, new_node_template, node); + rc = cib_conn->cmds->query(cib_conn, xpath, NULL, cib_xpath | cib_sync_call | cib_scope_local); + + if (rc == -ENXIO) { + xmlNode *cib_object = create_xml_node(NULL, XML_CIB_TAG_NODE); + + /* Using node uname as uuid ala corosync/openais */ + crm_xml_add(cib_object, XML_ATTR_ID, node); + crm_xml_add(cib_object, XML_ATTR_UNAME, node); + cib_conn->cmds->create(cib_conn, XML_CIB_TAG_NODES, cib_object, + cib_sync_call | cib_scope_local); + /* Not bothering with subsequent query to see if it exists, + we'll bomb out later in the call to query_node_uuid()... */ + + free_xml(cib_object); + } + + free(xpath); +} + +static lrmd_event_data_t * +create_op(xmlNode * cib_resource, const char *task, int interval, int outcome) +{ + lrmd_event_data_t *op = NULL; + xmlNode *xop = NULL; + + op = calloc(1, sizeof(lrmd_event_data_t)); + + op->rsc_id = strdup(ID(cib_resource)); + op->interval = interval; + op->op_type = strdup(task); + + op->rc = outcome; + op->op_status = 0; + op->params = NULL; /* TODO: Fill me in */ + op->t_run = time(NULL); + op->t_rcchange = op->t_run; + + op->call_id = 0; + for (xop = __xml_first_child(cib_resource); xop != NULL; xop = __xml_next(xop)) { + int tmp = 0; + + crm_element_value_int(xop, XML_LRM_ATTR_CALLID, &tmp); + if (tmp > op->call_id) { + op->call_id = tmp; + } + } + op->call_id++; + + return op; +} + +static xmlNode * +inject_op(xmlNode * cib_resource, lrmd_event_data_t * op, int target_rc) +{ + return create_operation_update(cib_resource, op, CRM_FEATURE_SET, target_rc, crm_system_name, + LOG_DEBUG_2); +} + +static xmlNode * +inject_node_state(cib_t * cib_conn, const char *node, const char *uuid) +{ + int rc = pcmk_ok; + int max = strlen(rsc_template) + strlen(node) + 1; + char *xpath = NULL; + xmlNode *cib_object = NULL; + + xpath = calloc(1, max); + + if (bringing_nodes_online) { + create_node_entry(cib_conn, node); + } + + snprintf(xpath, max, node_template, node); + rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object, + cib_xpath | cib_sync_call | cib_scope_local); + + if (cib_object && ID(cib_object) == NULL) { + crm_err("Detected multiple node_state entries for xpath=%s, bailing", xpath); + crm_log_xml_warn(cib_object, "Duplicates"); + crm_exit(ENOTUNIQ); + } + + if (rc == -ENXIO) { + char *found_uuid = NULL; + + if (uuid == NULL) { + query_node_uuid(cib_conn, node, &found_uuid, NULL); + } else { + found_uuid = strdup(uuid); + } + + cib_object = create_xml_node(NULL, XML_CIB_TAG_STATE); + crm_xml_add(cib_object, XML_ATTR_UUID, found_uuid); + crm_xml_add(cib_object, XML_ATTR_UNAME, node); + cib_conn->cmds->create(cib_conn, XML_CIB_TAG_STATUS, cib_object, + cib_sync_call | cib_scope_local); + free_xml(cib_object); + free(found_uuid); + + rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object, + cib_xpath | cib_sync_call | cib_scope_local); + crm_trace("injecting node state for %s. rc is %d", node, rc); + } + + free(xpath); + CRM_ASSERT(rc == pcmk_ok); + return cib_object; +} + +static xmlNode * +modify_node(cib_t * cib_conn, char *node, gboolean up) +{ + xmlNode *cib_node = inject_node_state(cib_conn, node, NULL); + + if (up) { + crm_xml_add(cib_node, XML_NODE_IN_CLUSTER, XML_BOOLEAN_YES); + crm_xml_add(cib_node, XML_NODE_IS_PEER, ONLINESTATUS); + crm_xml_add(cib_node, XML_NODE_JOIN_STATE, CRMD_JOINSTATE_MEMBER); + crm_xml_add(cib_node, XML_NODE_EXPECTED, CRMD_JOINSTATE_MEMBER); + + } else { + crm_xml_add(cib_node, XML_NODE_IN_CLUSTER, XML_BOOLEAN_NO); + crm_xml_add(cib_node, XML_NODE_IS_PEER, OFFLINESTATUS); + crm_xml_add(cib_node, XML_NODE_JOIN_STATE, CRMD_JOINSTATE_DOWN); + crm_xml_add(cib_node, XML_NODE_EXPECTED, CRMD_JOINSTATE_DOWN); + } + + crm_xml_add(cib_node, XML_ATTR_ORIGIN, crm_system_name); + return cib_node; +} + +static xmlNode * +find_resource_xml(xmlNode * cib_node, const char *resource) +{ + char *xpath = NULL; + xmlNode *match = NULL; + const char *node = crm_element_value(cib_node, XML_ATTR_UNAME); + int max = strlen(rsc_template) + strlen(resource) + strlen(node) + 1; + + xpath = calloc(1, max); + + snprintf(xpath, max, rsc_template, node, resource); + match = get_xpath_object(xpath, cib_node, LOG_DEBUG_2); + + free(xpath); + return match; +} + + +static xmlNode * +inject_resource(xmlNode * cib_node, const char *resource, const char *rclass, const char *rtype, + const char *rprovider) +{ + xmlNode *lrm = NULL; + xmlNode *container = NULL; + xmlNode *cib_resource = NULL; + char *xpath = NULL; + + cib_resource = find_resource_xml(cib_node, resource); + if (cib_resource != NULL) { + return cib_resource; + } + + /* One day, add query for class, provider, type */ + + if (rclass == NULL || rtype == NULL) { + fprintf(stderr, "Resource %s not found in the status section of %s." + " Please supply the class and type to continue\n", resource, ID(cib_node)); + return NULL; + + } else if (safe_str_neq(rclass, "ocf") + && safe_str_neq(rclass, "stonith") + && safe_str_neq(rclass, "heartbeat") + && safe_str_neq(rclass, "service") + && safe_str_neq(rclass, "upstart") + && safe_str_neq(rclass, "systemd") + && safe_str_neq(rclass, "lsb")) { + fprintf(stderr, "Invalid class for %s: %s\n", resource, rclass); + return NULL; + + } else if (safe_str_eq(rclass, "ocf") && rprovider == NULL) { + fprintf(stderr, "Please specify the provider for resource %s\n", resource); + return NULL; + } + + xpath = (char *)xmlGetNodePath(cib_node); + crm_info("Injecting new resource %s into %s '%s'", resource, xpath, ID(cib_node)); + free(xpath); + + lrm = first_named_child(cib_node, XML_CIB_TAG_LRM); + if (lrm == NULL) { + const char *node_uuid = ID(cib_node); + + lrm = create_xml_node(cib_node, XML_CIB_TAG_LRM); + crm_xml_add(lrm, XML_ATTR_ID, node_uuid); + } + + container = first_named_child(lrm, XML_LRM_TAG_RESOURCES); + if (container == NULL) { + container = create_xml_node(lrm, XML_LRM_TAG_RESOURCES); + } + + cib_resource = create_xml_node(container, XML_LRM_TAG_RESOURCE); + crm_xml_add(cib_resource, XML_ATTR_ID, resource); + + crm_xml_add(cib_resource, XML_AGENT_ATTR_CLASS, rclass); + crm_xml_add(cib_resource, XML_AGENT_ATTR_PROVIDER, rprovider); + crm_xml_add(cib_resource, XML_ATTR_TYPE, rtype); + + return cib_resource; +} + +static int +find_ticket_state(cib_t * the_cib, const char *ticket_id, xmlNode ** ticket_state_xml) +{ + int offset = 0; + static int xpath_max = 1024; + int rc = pcmk_ok; + xmlNode *xml_search = NULL; + + char *xpath_string = NULL; + + CRM_ASSERT(ticket_state_xml != NULL); + *ticket_state_xml = NULL; + + xpath_string = calloc(1, xpath_max); + offset += snprintf(xpath_string + offset, xpath_max - offset, "%s", "/cib/status/tickets"); + + if (ticket_id) { + offset += snprintf(xpath_string + offset, xpath_max - offset, "/%s[@id=\"%s\"]", + XML_CIB_TAG_TICKET_STATE, ticket_id); + } + CRM_LOG_ASSERT(offset > 0); + rc = the_cib->cmds->query(the_cib, xpath_string, &xml_search, + cib_sync_call | cib_scope_local | cib_xpath); + + if (rc != pcmk_ok) { + goto bail; + } + + crm_log_xml_debug(xml_search, "Match"); + if (xml_has_children(xml_search)) { + if (ticket_id) { + fprintf(stdout, "Multiple ticket_states match ticket_id=%s\n", ticket_id); + } + *ticket_state_xml = xml_search; + } else { + *ticket_state_xml = xml_search; + } + + bail: + free(xpath_string); + return rc; +} + +static int +set_ticket_state_attr(const char *ticket_id, const char *attr_name, + const char *attr_value, cib_t * cib, int cib_options) +{ + int rc = pcmk_ok; + xmlNode *xml_top = NULL; + xmlNode *ticket_state_xml = NULL; + + rc = find_ticket_state(cib, ticket_id, &ticket_state_xml); + if (rc == pcmk_ok) { + crm_debug("Found a match state for ticket: id=%s", ticket_id); + xml_top = ticket_state_xml; + + } else if (rc != -ENXIO) { + return rc; + + } else { + xmlNode *xml_obj = NULL; + + xml_top = create_xml_node(NULL, XML_CIB_TAG_STATUS); + xml_obj = create_xml_node(xml_top, XML_CIB_TAG_TICKETS); + ticket_state_xml = create_xml_node(xml_obj, XML_CIB_TAG_TICKET_STATE); + crm_xml_add(ticket_state_xml, XML_ATTR_ID, ticket_id); + } + + crm_xml_add(ticket_state_xml, attr_name, attr_value); + + crm_log_xml_debug(xml_top, "Update"); + + rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, xml_top, cib_options); + + free_xml(xml_top); + + return rc; +} + +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 rc = pcmk_ok; + GListPtr gIter = NULL; + + xmlNode *cib_op = NULL; + xmlNode *cib_node = NULL; + xmlNode *cib_resource = NULL; + + lrmd_event_data_t *op = NULL; + + if (quorum) { + xmlNode *top = create_xml_node(NULL, XML_TAG_CIB); + + quiet_log(" + Setting quorum: %s\n", quorum); + /* crm_xml_add(top, XML_ATTR_DC_UUID, dc_uuid); */ + crm_xml_add(top, XML_ATTR_HAVE_QUORUM, quorum); + + rc = cib->cmds->modify(cib, NULL, top, cib_sync_call | cib_scope_local); + CRM_ASSERT(rc == pcmk_ok); + } + + if (watchdog) { + quiet_log(" + Setting watchdog: %s\n", watchdog); + + rc = update_attr_delegate(cib, cib_sync_call | cib_scope_local, + XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL, NULL, + XML_ATTR_HAVE_WATCHDOG, watchdog, FALSE, NULL, NULL); + + CRM_ASSERT(rc == pcmk_ok); + } + + for (gIter = node_up; gIter != NULL; gIter = gIter->next) { + char *node = (char *)gIter->data; + + quiet_log(" + Bringing node %s online\n", node); + cib_node = modify_node(cib, node, TRUE); + CRM_ASSERT(cib_node != NULL); + + rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node, + cib_sync_call | cib_scope_local); + CRM_ASSERT(rc == pcmk_ok); + free_xml(cib_node); + } + + for (gIter = node_down; gIter != NULL; gIter = gIter->next) { + char xpath[STATUS_PATH_MAX]; + char *node = (char *)gIter->data; + + quiet_log(" + Taking node %s offline\n", node); + cib_node = modify_node(cib, node, FALSE); + CRM_ASSERT(cib_node != NULL); + + rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node, + cib_sync_call | cib_scope_local); + CRM_ASSERT(rc == pcmk_ok); + free_xml(cib_node); + + snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", node, XML_CIB_TAG_LRM); + cib->cmds->delete(cib, xpath, NULL, + cib_xpath | cib_sync_call | cib_scope_local); + + snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", node, + XML_TAG_TRANSIENT_NODEATTRS); + cib->cmds->delete(cib, xpath, NULL, + cib_xpath | cib_sync_call | cib_scope_local); + + } + + for (gIter = node_fail; gIter != NULL; gIter = gIter->next) { + char *node = (char *)gIter->data; + + quiet_log(" + Failing node %s\n", node); + cib_node = modify_node(cib, node, TRUE); + crm_xml_add(cib_node, XML_NODE_IN_CLUSTER, XML_BOOLEAN_NO); + CRM_ASSERT(cib_node != NULL); + + rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node, + cib_sync_call | cib_scope_local); + CRM_ASSERT(rc == pcmk_ok); + free_xml(cib_node); + } + + for (gIter = ticket_grant; gIter != NULL; gIter = gIter->next) { + char *ticket_id = (char *)gIter->data; + + quiet_log(" + Granting ticket %s\n", ticket_id); + rc = set_ticket_state_attr(ticket_id, "granted", "true", + cib, cib_sync_call | cib_scope_local); + + CRM_ASSERT(rc == pcmk_ok); + } + + for (gIter = ticket_revoke; gIter != NULL; gIter = gIter->next) { + char *ticket_id = (char *)gIter->data; + + quiet_log(" + Revoking ticket %s\n", ticket_id); + rc = set_ticket_state_attr(ticket_id, "granted", "false", + cib, cib_sync_call | cib_scope_local); + + CRM_ASSERT(rc == pcmk_ok); + } + + for (gIter = ticket_standby; gIter != NULL; gIter = gIter->next) { + char *ticket_id = (char *)gIter->data; + + quiet_log(" + Making ticket %s standby\n", ticket_id); + rc = set_ticket_state_attr(ticket_id, "standby", "true", + cib, cib_sync_call | cib_scope_local); + + CRM_ASSERT(rc == pcmk_ok); + } + + for (gIter = ticket_activate; gIter != NULL; gIter = gIter->next) { + char *ticket_id = (char *)gIter->data; + + quiet_log(" + Activating ticket %s\n", ticket_id); + rc = set_ticket_state_attr(ticket_id, "standby", "false", + cib, cib_sync_call | cib_scope_local); + + CRM_ASSERT(rc == pcmk_ok); + } + + for (gIter = op_inject; gIter != NULL; gIter = gIter->next) { + char *spec = (char *)gIter->data; + + int rc = 0; + int outcome = 0; + int interval = 0; + + char *key = NULL; + char *node = NULL; + char *task = NULL; + char *resource = NULL; + + const char *rtype = NULL; + const char *rclass = NULL; + const char *rprovider = NULL; + + resource_t *rsc = NULL; + + quiet_log(" + Injecting %s into the configuration\n", spec); + + key = calloc(1, strlen(spec) + 1); + node = calloc(1, strlen(spec) + 1); + rc = sscanf(spec, "%[^@]@%[^=]=%d", key, node, &outcome); + CRM_CHECK(rc == 3, + fprintf(stderr, "Invalid operation spec: %s. Only found %d fields\n", spec, rc); + continue); + + parse_op_key(key, &resource, &task, &interval); + + rsc = pe_find_resource(data_set->resources, resource); + if (rsc == NULL) { + fprintf(stderr, " - Invalid resource name: %s\n", resource); + } else { + rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); + rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE); + rprovider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); + + cib_node = inject_node_state(cib, node, NULL); + CRM_ASSERT(cib_node != NULL); + + update_failcounts(cib_node, resource, interval, outcome); + + cib_resource = inject_resource(cib_node, resource, rclass, rtype, rprovider); + CRM_ASSERT(cib_resource != NULL); + + op = create_op(cib_resource, task, interval, outcome); + CRM_ASSERT(op != NULL); + + cib_op = inject_op(cib_resource, op, 0); + CRM_ASSERT(cib_op != NULL); + lrmd_free_event(op); + + rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node, + cib_sync_call | cib_scope_local); + CRM_ASSERT(rc == pcmk_ok); + } + free(task); + free(node); + free(key); + } +} + +static gboolean +exec_pseudo_action(crm_graph_t * graph, crm_action_t * action) +{ + const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); + const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); + + action->confirmed = TRUE; + + quiet_log(" * Pseudo action: %s%s%s\n", task, node ? " on " : "", node ? node : ""); + update_graph(graph, action); + return TRUE; +} + +static gboolean +exec_rsc_action(crm_graph_t * graph, crm_action_t * action) +{ + int rc = 0; + GListPtr gIter = NULL; + lrmd_event_data_t *op = NULL; + int target_outcome = 0; + gboolean uname_is_uuid = FALSE; + + const char *rtype = NULL; + const char *rclass = NULL; + const char *resource = NULL; + const char *rprovider = NULL; + const char *operation = crm_element_value(action->xml, "operation"); + const char *target_rc_s = crm_meta_value(action->params, XML_ATTR_TE_TARGET_RC); + + xmlNode *cib_node = NULL; + xmlNode *cib_resource = NULL; + xmlNode *action_rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE); + + char *node = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET); + char *uuid = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET_UUID); + const char *router_node = crm_element_value(action->xml, XML_LRM_ATTR_ROUTER_NODE); + + if (safe_str_eq(operation, CRM_OP_PROBED) + || safe_str_eq(operation, CRM_OP_REPROBE)) { + crm_info("Skipping %s op for %s\n", operation, node); + goto done; + } + + if (action_rsc == NULL) { + crm_log_xml_err(action->xml, "Bad"); + free(node); free(uuid); + return FALSE; + } + + /* Look for the preferred name + * If not found, try the expected 'local' name + * If not found use the preferred name anyway + */ + resource = crm_element_value(action_rsc, XML_ATTR_ID); + if (pe_find_resource(fake_resource_list, resource) == NULL) { + const char *longname = crm_element_value(action_rsc, XML_ATTR_ID_LONG); + + if (pe_find_resource(fake_resource_list, longname)) { + resource = longname; + } + } + + if (safe_str_eq(operation, "delete")) { + quiet_log(" * Resource action: %-15s delete on %s\n", resource, node); + goto done; + } + + rclass = crm_element_value(action_rsc, XML_AGENT_ATTR_CLASS); + rtype = crm_element_value(action_rsc, XML_ATTR_TYPE); + rprovider = crm_element_value(action_rsc, XML_AGENT_ATTR_PROVIDER); + + if (target_rc_s != NULL) { + target_outcome = crm_parse_int(target_rc_s, "0"); + } + + CRM_ASSERT(fake_cib->cmds->query(fake_cib, NULL, NULL, cib_sync_call | cib_scope_local) == + pcmk_ok); + + if (router_node) { + uname_is_uuid = TRUE; + } + + cib_node = inject_node_state(fake_cib, node, uname_is_uuid ? node : uuid); + CRM_ASSERT(cib_node != NULL); + + cib_resource = inject_resource(cib_node, resource, rclass, rtype, rprovider); + CRM_ASSERT(cib_resource != NULL); + + op = convert_graph_action(cib_resource, action, 0, target_outcome); + if (op->interval) { + quiet_log(" * Resource action: %-15s %s=%d on %s\n", resource, op->op_type, op->interval, + node); + } else { + quiet_log(" * Resource action: %-15s %s on %s\n", resource, op->op_type, node); + } + + for (gIter = fake_op_fail_list; gIter != NULL; gIter = gIter->next) { + char *spec = (char *)gIter->data; + char *key = NULL; + + key = calloc(1, 1 + strlen(spec)); + snprintf(key, strlen(spec), "%s_%s_%d@%s=", resource, op->op_type, op->interval, node); + + if (strncasecmp(key, spec, strlen(key)) == 0) { + sscanf(spec, "%*[^=]=%d", (int *)&op->rc); + + action->failed = TRUE; + graph->abort_priority = INFINITY; + printf("\tPretending action %d failed with rc=%d\n", action->id, op->rc); + update_failcounts(cib_node, resource, op->interval, op->rc); + free(key); + break; + } + free(key); + } + + inject_op(cib_resource, op, target_outcome); + lrmd_free_event(op); + + rc = fake_cib->cmds->modify(fake_cib, XML_CIB_TAG_STATUS, cib_node, + cib_sync_call | cib_scope_local); + CRM_ASSERT(rc == pcmk_ok); + + done: + free(node); free(uuid); + free_xml(cib_node); + action->confirmed = TRUE; + update_graph(graph, action); + return TRUE; +} + +static gboolean +exec_crmd_action(crm_graph_t * graph, crm_action_t * action) +{ + const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); + const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); + xmlNode *rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE); + + action->confirmed = TRUE; + + if(rsc) { + quiet_log(" * Cluster action: %s for %s on %s\n", task, ID(rsc), node); + } else { + quiet_log(" * Cluster action: %s on %s\n", task, node); + } + update_graph(graph, action); + return TRUE; +} + +static gboolean +exec_stonith_action(crm_graph_t * graph, crm_action_t * action) +{ + const char *op = crm_meta_value(action->params, "stonith_action"); + char *target = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET); + + quiet_log(" * Fencing %s (%s)\n", target, op); + if(safe_str_neq(op, "on")) { + int rc = 0; + char xpath[STATUS_PATH_MAX]; + xmlNode *cib_node = modify_node(fake_cib, target, FALSE); + + crm_xml_add(cib_node, XML_ATTR_ORIGIN, __FUNCTION__); + CRM_ASSERT(cib_node != NULL); + + rc = fake_cib->cmds->replace(fake_cib, XML_CIB_TAG_STATUS, cib_node, + cib_sync_call | cib_scope_local); + CRM_ASSERT(rc == pcmk_ok); + + snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", target, XML_CIB_TAG_LRM); + fake_cib->cmds->delete(fake_cib, xpath, NULL, + cib_xpath | cib_sync_call | cib_scope_local); + + snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", target, + XML_TAG_TRANSIENT_NODEATTRS); + fake_cib->cmds->delete(fake_cib, xpath, NULL, + cib_xpath | cib_sync_call | cib_scope_local); + + free_xml(cib_node); + } + + action->confirmed = TRUE; + update_graph(graph, action); + free(target); + return TRUE; +} + +int +run_simulation(pe_working_set_t * data_set, cib_t *cib, GListPtr op_fail_list, bool quiet) +{ + crm_graph_t *transition = NULL; + enum transition_status graph_rc = -1; + + crm_graph_functions_t exec_fns = { + exec_pseudo_action, + exec_rsc_action, + exec_crmd_action, + exec_stonith_action, + }; + + fake_cib = cib; + fake_quiet = quiet; + fake_op_fail_list = op_fail_list; + + quiet_log("\nExecuting cluster transition:\n"); + + set_graph_functions(&exec_fns); + transition = unpack_graph(data_set->graph, crm_system_name); + print_graph(LOG_DEBUG, transition); + + fake_resource_list = data_set->resources; + do { + graph_rc = run_graph(transition); + + } while (graph_rc == transition_active); + fake_resource_list = NULL; + + if (graph_rc != transition_complete) { + fprintf(stdout, "Transition failed: %s\n", transition_status(graph_rc)); + print_graph(LOG_ERR, transition); + } + destroy_graph(transition); + if (graph_rc != transition_complete) { + fprintf(stdout, "An invalid transition was produced\n"); + } + + if (quiet == FALSE) { + xmlNode *cib_object = NULL; + int rc = fake_cib->cmds->query(fake_cib, NULL, &cib_object, cib_sync_call | cib_scope_local); + + CRM_ASSERT(rc == pcmk_ok); + cleanup_alloc_calculations(data_set); + data_set->input = cib_object; + } + + if (graph_rc != transition_complete) { + return graph_rc; + } + return 0; +} diff --git a/tools/fake_transition.h b/tools/fake_transition.h new file mode 100644 index 0000000..2ee7af9 --- /dev/null +++ b/tools/fake_transition.h @@ -0,0 +1,8 @@ +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); +