Page MenuHomeClusterLabs Projects

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/lib/fencing/st_output.c b/lib/fencing/st_output.c
index 04f4b831c9..7c3ccef2bb 100644
--- a/lib/fencing/st_output.c
+++ b/lib/fencing/st_output.c
@@ -1,467 +1,467 @@
/*
* Copyright 2019-2020 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <stdarg.h>
#include <crm/stonith-ng.h>
#include <crm/common/iso8601.h>
#include <crm/common/util.h>
#include <crm/common/xml.h>
#include <crm/common/output_internal.h>
#include <crm/common/xml_internal.h>
#include <crm/fencing/internal.h>
#include <crm/pengine/internal.h>
static char *
time_t_string(time_t when) {
crm_time_t *crm_when = crm_time_new(NULL);
char *buf = NULL;
crm_time_set_timet(crm_when, &when);
buf = crm_time_as_string(crm_when, crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
crm_time_free(crm_when);
return buf;
}
-PCMK__OUTPUT_ARGS("failed-fencing-history", "stonith_history_t *", "GListPtr", "gboolean", "gboolean")
+PCMK__OUTPUT_ARGS("failed-fencing-history", "stonith_history_t *", "GList *", "gboolean", "gboolean")
int
stonith__failed_history(pcmk__output_t *out, va_list args) {
stonith_history_t *history = va_arg(args, stonith_history_t *);
- GListPtr only_node = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
gboolean full_history = va_arg(args, gboolean);
gboolean print_spacer = va_arg(args, gboolean);
int rc = pcmk_rc_no_output;
for (stonith_history_t *hp = history; hp; hp = hp->next) {
if (hp->state != st_failed) {
continue;
}
if (!pcmk__str_in_list(only_node, hp->target)) {
continue;
}
PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Failed Fencing Actions");
out->message(out, "stonith-event", hp, full_history, stonith__later_succeeded(hp, history));
out->increment_list(out);
}
PCMK__OUTPUT_LIST_FOOTER(out, rc);
return rc;
}
-PCMK__OUTPUT_ARGS("fencing-history", "stonith_history_t *", "GListPtr", "gboolean", "gboolean")
+PCMK__OUTPUT_ARGS("fencing-history", "stonith_history_t *", "GList *", "gboolean", "gboolean")
int
stonith__history(pcmk__output_t *out, va_list args) {
stonith_history_t *history = va_arg(args, stonith_history_t *);
- GListPtr only_node = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
gboolean full_history = va_arg(args, gboolean);
gboolean print_spacer = va_arg(args, gboolean);
int rc = pcmk_rc_no_output;
for (stonith_history_t *hp = history; hp; hp = hp->next) {
if (!pcmk__str_in_list(only_node, hp->target)) {
continue;
}
if (hp->state != st_failed) {
PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Fencing History");
out->message(out, "stonith-event", hp, full_history, stonith__later_succeeded(hp, history));
out->increment_list(out);
}
}
PCMK__OUTPUT_LIST_FOOTER(out, rc);
return rc;
}
-PCMK__OUTPUT_ARGS("full-fencing-history", "crm_exit_t", "stonith_history_t *", "GListPtr", "gboolean", "gboolean")
+PCMK__OUTPUT_ARGS("full-fencing-history", "crm_exit_t", "stonith_history_t *", "GList *", "gboolean", "gboolean")
int
stonith__full_history(pcmk__output_t *out, va_list args) {
crm_exit_t history_rc G_GNUC_UNUSED = va_arg(args, crm_exit_t);
stonith_history_t *history = va_arg(args, stonith_history_t *);
- GListPtr only_node = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
gboolean full_history = va_arg(args, gboolean);
gboolean print_spacer = va_arg(args, gboolean);
int rc = pcmk_rc_no_output;
for (stonith_history_t *hp = history; hp; hp = hp->next) {
if (!pcmk__str_in_list(only_node, hp->target)) {
continue;
}
PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Fencing History");
out->message(out, "stonith-event", hp, full_history, stonith__later_succeeded(hp, history));
out->increment_list(out);
}
PCMK__OUTPUT_LIST_FOOTER(out, rc);
return rc;
}
-PCMK__OUTPUT_ARGS("full-fencing-history", "crm_exit_t", "stonith_history_t *", "GListPtr", "gboolean", "gboolean")
+PCMK__OUTPUT_ARGS("full-fencing-history", "crm_exit_t", "stonith_history_t *", "GList *", "gboolean", "gboolean")
int
stonith__full_history_xml(pcmk__output_t *out, va_list args) {
crm_exit_t history_rc = va_arg(args, crm_exit_t);
stonith_history_t *history = va_arg(args, stonith_history_t *);
- GListPtr only_node = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
gboolean full_history = va_arg(args, gboolean);
gboolean print_spacer G_GNUC_UNUSED = va_arg(args, gboolean);
int rc = pcmk_rc_no_output;
if (history_rc == 0) {
for (stonith_history_t *hp = history; hp; hp = hp->next) {
if (!pcmk__str_in_list(only_node, hp->target)) {
continue;
}
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Fencing History");
out->message(out, "stonith-event", hp, full_history, stonith__later_succeeded(hp, history));
out->increment_list(out);
}
PCMK__OUTPUT_LIST_FOOTER(out, rc);
} else {
char *rc_s = crm_itoa(history_rc);
pcmk__output_create_xml_node(out, "fence_history",
"status", rc_s,
NULL);
free(rc_s);
rc = pcmk_rc_ok;
}
return rc;
}
PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
int
stonith__last_fenced_html(pcmk__output_t *out, va_list args) {
const char *target = va_arg(args, const char *);
time_t when = va_arg(args, time_t);
if (when) {
char *buf = crm_strdup_printf("Node %s last fenced at: %s", target, ctime(&when));
pcmk__output_create_html_node(out, "div", NULL, NULL, buf);
free(buf);
return pcmk_rc_ok;
} else {
return pcmk_rc_no_output;
}
}
PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
int
stonith__last_fenced_text(pcmk__output_t *out, va_list args) {
const char *target = va_arg(args, const char *);
time_t when = va_arg(args, time_t);
if (when) {
pcmk__indented_printf(out, "Node %s last fenced at: %s", target, ctime(&when));
} else {
pcmk__indented_printf(out, "Node %s has never been fenced\n", target);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
int
stonith__last_fenced_xml(pcmk__output_t *out, va_list args) {
const char *target = va_arg(args, const char *);
time_t when = va_arg(args, time_t);
if (when) {
char *buf = time_t_string(when);
pcmk__output_create_xml_node(out, "last-fenced",
"target", target,
"when", buf,
NULL);
free(buf);
return pcmk_rc_ok;
} else {
return pcmk_rc_no_output;
}
}
-PCMK__OUTPUT_ARGS("pending-fencing-actions", "stonith_history_t *", "GListPtr", "gboolean", "gboolean")
+PCMK__OUTPUT_ARGS("pending-fencing-actions", "stonith_history_t *", "GList *", "gboolean", "gboolean")
int
stonith__pending_actions(pcmk__output_t *out, va_list args) {
stonith_history_t *history = va_arg(args, stonith_history_t *);
- GListPtr only_node = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
gboolean full_history = va_arg(args, gboolean);
gboolean print_spacer = va_arg(args, gboolean);
int rc = pcmk_rc_no_output;
for (stonith_history_t *hp = history; hp; hp = hp->next) {
if (!pcmk__str_in_list(only_node, hp->target)) {
continue;
}
/* Skip the rest of the history after we see a failed/done action */
if ((hp->state == st_failed) || (hp->state == st_done)) {
break;
}
PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Pending Fencing Actions");
out->message(out, "stonith-event", hp, full_history, stonith__later_succeeded(hp, history));
out->increment_list(out);
}
PCMK__OUTPUT_LIST_FOOTER(out, rc);
return rc;
}
PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "gboolean", "gboolean")
int
stonith__event_html(pcmk__output_t *out, va_list args) {
stonith_history_t *event = va_arg(args, stonith_history_t *);
gboolean full_history = va_arg(args, gboolean);
gboolean later_succeeded = va_arg(args, gboolean);
switch(event->state) {
case st_done: {
char *completed_s = time_t_string(event->completed);
out->list_item(out, "successful-stonith-event",
"%s of %s successful: delegate=%s, client=%s, origin=%s, %s='%s'",
stonith_action_str(event->action), event->target,
event->delegate ? event->delegate : "",
event->client, event->origin,
full_history ? "completed" : "last-successful",
completed_s);
free(completed_s);
break;
}
case st_failed: {
char *failed_s = time_t_string(event->completed);
out->list_item(out, "failed-stonith-event",
"%s of %s failed : delegate=%s, client=%s, origin=%s, %s='%s' %s",
stonith_action_str(event->action), event->target,
event->delegate ? event->delegate : "",
event->client, event->origin,
full_history ? "completed" : "last-failed",
failed_s,
later_succeeded ? "(a later attempt succeeded)" : "");
free(failed_s);
break;
}
default:
out->list_item(out, "pending-stonith-event",
"%s of %s pending: client=%s, origin=%s",
stonith_action_str(event->action), event->target,
event->client, event->origin);
break;
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "gboolean", "gboolean")
int
stonith__event_text(pcmk__output_t *out, va_list args) {
stonith_history_t *event = va_arg(args, stonith_history_t *);
gboolean full_history = va_arg(args, gboolean);
gboolean later_succeeded = va_arg(args, gboolean);
char *buf = time_t_string(event->completed);
switch (event->state) {
case st_failed:
pcmk__indented_printf(out, "%s of %s failed: delegate=%s, client=%s, origin=%s, %s='%s' %s\n",
stonith_action_str(event->action), event->target,
event->delegate ? event->delegate : "",
event->client, event->origin,
full_history ? "completed" : "last-failed", buf,
later_succeeded ? "(a later attempt succeeded)" : "");
break;
case st_done:
pcmk__indented_printf(out, "%s of %s successful: delegate=%s, client=%s, origin=%s, %s='%s'\n",
stonith_action_str(event->action), event->target,
event->delegate ? event->delegate : "",
event->client, event->origin,
full_history ? "completed" : "last-successful", buf);
break;
default:
pcmk__indented_printf(out, "%s of %s pending: client=%s, origin=%s\n",
stonith_action_str(event->action), event->target,
event->client, event->origin);
break;
}
free(buf);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "gboolean", "gboolean")
int
stonith__event_xml(pcmk__output_t *out, va_list args) {
stonith_history_t *event = va_arg(args, stonith_history_t *);
gboolean full_history G_GNUC_UNUSED = va_arg(args, gboolean);
gboolean later_succeeded G_GNUC_UNUSED = va_arg(args, gboolean);
char *buf = NULL;
xmlNodePtr node = pcmk__output_create_xml_node(out, "fence_event",
"action", event->action,
"target", event->target,
"client", event->client,
"origin", event->origin,
NULL);
switch (event->state) {
case st_failed:
crm_xml_add(node, "status", "failed");
break;
case st_done:
crm_xml_add(node, "status", "success");
break;
default: {
char *state = crm_itoa(event->state);
pcmk__xe_set_props(node, "status", "pending",
"extended-status", state,
NULL);
free(state);
break;
}
}
if (event->delegate != NULL) {
crm_xml_add(node, "delegate", event->delegate);
}
if (event->state == st_failed || event->state == st_done) {
buf = time_t_string(event->completed);
crm_xml_add(node, "completed", buf);
free(buf);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "char *", "char *", "int")
int
stonith__validate_agent_html(pcmk__output_t *out, va_list args) {
const char *agent = va_arg(args, const char *);
const char *device = va_arg(args, const char *);
char *output = va_arg(args, char *);
char *error_output = va_arg(args, char *);
int rc = va_arg(args, int);
if (device) {
char *buf = crm_strdup_printf("Validation of %s on %s %s", agent, device,
rc ? "failed" : "succeeded");
pcmk__output_create_html_node(out, "div", NULL, NULL, buf);
free(buf);
} else {
char *buf = crm_strdup_printf("Validation of %s %s", agent,
rc ? "failed" : "succeeded");
pcmk__output_create_html_node(out, "div", NULL, NULL, buf);
free(buf);
}
out->subprocess_output(out, rc, output, error_output);
return rc;
}
PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "char *", "char *", "int")
int
stonith__validate_agent_text(pcmk__output_t *out, va_list args) {
const char *agent = va_arg(args, const char *);
const char *device = va_arg(args, const char *);
char *output = va_arg(args, char *);
char *error_output = va_arg(args, char *);
int rc = va_arg(args, int);
if (device) {
pcmk__indented_printf(out, "Validation of %s on %s %s\n", agent, device,
rc ? "failed" : "succeeded");
} else {
pcmk__indented_printf(out, "Validation of %s %s\n", agent,
rc ? "failed" : "succeeded");
}
if (output) {
puts(output);
}
if (error_output) {
puts(error_output);
}
return rc;
}
PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "char *", "char *", "int")
int
stonith__validate_agent_xml(pcmk__output_t *out, va_list args) {
const char *agent = va_arg(args, const char *);
const char *device = va_arg(args, const char *);
char *output = va_arg(args, char *);
char *error_output = va_arg(args, char *);
int rc = va_arg(args, int);
xmlNodePtr node = pcmk__output_create_xml_node(out, "validate",
"agent", agent,
"valid", pcmk__btoa(rc),
NULL);
if (device != NULL) {
crm_xml_add(node, "device", device);
}
pcmk__output_xml_push_parent(out, node);
out->subprocess_output(out, rc, output, error_output);
pcmk__output_xml_pop_parent(out);
return rc;
}
static pcmk__message_entry_t fmt_functions[] = {
{ "failed-fencing-history", "default", stonith__failed_history },
{ "fencing-history", "default", stonith__history },
{ "full-fencing-history", "default", stonith__full_history },
{ "full-fencing-history", "xml", stonith__full_history_xml },
{ "last-fenced", "html", stonith__last_fenced_html },
{ "last-fenced", "log", stonith__last_fenced_text },
{ "last-fenced", "text", stonith__last_fenced_text },
{ "last-fenced", "xml", stonith__last_fenced_xml },
{ "pending-fencing-actions", "default", stonith__pending_actions },
{ "stonith-event", "html", stonith__event_html },
{ "stonith-event", "log", stonith__event_text },
{ "stonith-event", "text", stonith__event_text },
{ "stonith-event", "xml", stonith__event_xml },
{ "validate", "html", stonith__validate_agent_html },
{ "validate", "log", stonith__validate_agent_text },
{ "validate", "text", stonith__validate_agent_text },
{ "validate", "xml", stonith__validate_agent_xml },
{ NULL, NULL, NULL }
};
void
stonith__register_messages(pcmk__output_t *out) {
pcmk__register_messages(out, fmt_functions);
}
diff --git a/lib/pacemaker/pcmk_output.c b/lib/pacemaker/pcmk_output.c
index 74a7c59326..a0b12b9998 100644
--- a/lib/pacemaker/pcmk_output.c
+++ b/lib/pacemaker/pcmk_output.c
@@ -1,550 +1,550 @@
/*
* Copyright 2019-2020 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/results.h>
#include <crm/common/output_internal.h>
#include <crm/stonith-ng.h>
#include <crm/fencing/internal.h>
#include <libxml/tree.h>
#include <pacemaker-internal.h>
pcmk__supported_format_t pcmk__out_formats[] = {
PCMK__SUPPORTED_FORMAT_XML,
{ NULL, NULL, NULL }
};
int
pcmk__out_prologue(pcmk__output_t **out, xmlNodePtr *xml) {
int rc = pcmk_rc_ok;
if (*xml != NULL) {
xmlFreeNode(*xml);
}
pcmk__register_formats(NULL, pcmk__out_formats);
rc = pcmk__output_new(out, "xml", NULL, NULL);
if (rc != pcmk_rc_ok) {
return rc;
}
stonith__register_messages(*out);
return rc;
}
void
pcmk__out_epilogue(pcmk__output_t *out, xmlNodePtr *xml, int retval) {
if (retval == pcmk_rc_ok) {
out->finish(out, 0, FALSE, (void **) xml);
}
pcmk__output_free(out);
}
PCMK__OUTPUT_ARGS("colocations-list", "pe_resource_t *", "gboolean", "gboolean")
static int colocations_list(pcmk__output_t *out, va_list args) {
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
gboolean dependents = va_arg(args, gboolean);
gboolean recursive = va_arg(args, gboolean);
- GListPtr lpc = NULL;
- GListPtr list = rsc->rsc_cons;
+ GList *lpc = NULL;
+ GList *list = rsc->rsc_cons;
bool printed_header = false;
if (dependents) {
list = rsc->rsc_cons_lhs;
}
if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
return pcmk_rc_no_output;
}
pe__set_resource_flags(rsc, pe_rsc_allocating);
for (lpc = list; lpc != NULL; lpc = lpc->next) {
rsc_colocation_t *cons = (rsc_colocation_t *) lpc->data;
char *score = NULL;
pe_resource_t *peer = cons->rsc_rh;
if (dependents) {
peer = cons->rsc_lh;
}
if (pcmk_is_set(peer->flags, pe_rsc_allocating)) {
if (dependents == FALSE) {
if (!printed_header) {
out->begin_list(out, NULL, NULL, "Colocations");
printed_header = true;
}
out->list_item(out, NULL, "%s (id=%s - loop)", peer->id, cons->id);
}
continue;
}
if (dependents && recursive) {
if (!printed_header) {
out->begin_list(out, NULL, NULL, "Colocations");
printed_header = true;
}
out->message(out, "colocations-list", rsc, dependents, recursive);
}
if (!printed_header) {
out->begin_list(out, NULL, NULL, "Colocations");
printed_header = true;
}
score = score2char(cons->score);
if (cons->role_rh > RSC_ROLE_STARTED) {
out->list_item(out, NULL, "%s (score=%s, %s role=%s, id=%s",
peer->id, score, dependents ? "needs" : "with",
role2text(cons->role_rh), cons->id);
} else {
out->list_item(out, NULL, "%s (score=%s, id=%s",
peer->id, score, cons->id);
}
free(score);
out->message(out, "locations-list", peer);
if (!dependents && recursive) {
out->message(out, "colocations-list", rsc, dependents, recursive);
}
}
if (printed_header) {
out->end_list(out);
}
return pcmk_rc_no_output;
}
PCMK__OUTPUT_ARGS("colocations-list", "pe_resource_t *", "gboolean", "gboolean")
static int colocations_list_xml(pcmk__output_t *out, va_list args) {
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
gboolean dependents = va_arg(args, gboolean);
gboolean recursive = va_arg(args, gboolean);
- GListPtr lpc = NULL;
- GListPtr list = rsc->rsc_cons;
+ GList *lpc = NULL;
+ GList *list = rsc->rsc_cons;
bool printed_header = false;
if (dependents) {
list = rsc->rsc_cons_lhs;
}
if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
return pcmk_rc_ok;
}
pe__set_resource_flags(rsc, pe_rsc_allocating);
for (lpc = list; lpc != NULL; lpc = lpc->next) {
rsc_colocation_t *cons = (rsc_colocation_t *) lpc->data;
pe_resource_t *peer = cons->rsc_rh;
char *score = NULL;
if (dependents) {
peer = cons->rsc_lh;
}
if (pcmk_is_set(peer->flags, pe_rsc_allocating)) {
if (dependents == FALSE) {
if (!printed_header) {
pcmk__output_xml_create_parent(out, "colocations", NULL);
printed_header = true;
}
pcmk__output_create_xml_node(out, "colocation",
"peer", peer->id,
"id", cons->id,
NULL);
}
continue;
}
if (dependents && recursive) {
if (!printed_header) {
pcmk__output_xml_create_parent(out, "colocations", NULL);
printed_header = true;
}
out->message(out, "colocations-list", rsc, dependents, recursive);
}
if (!printed_header) {
pcmk__output_xml_create_parent(out, "colocations", NULL);
printed_header = true;
}
score = score2char(cons->score);
if (cons->role_rh > RSC_ROLE_STARTED) {
pcmk__output_create_xml_node(out, "colocation",
"peer", peer->id,
"id", cons->id,
"score", score,
"dependents", dependents ? "needs" : "with",
"role", role2text(cons->role_rh),
NULL);
} else {
pcmk__output_create_xml_node(out, "colocation",
"peer", peer->id,
"id", cons->id,
"score", score,
NULL);
}
free(score);
out->message(out, "locations-list", peer);
if (!dependents && recursive) {
out->message(out, "colocations-list", rsc, dependents, recursive);
}
}
if (printed_header) {
pcmk__output_xml_pop_parent(out);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("locations-list", "pe_resource_t *")
static int locations_list(pcmk__output_t *out, va_list args) {
pe_resource_t *rsc G_GNUC_UNUSED = va_arg(args, pe_resource_t *);
- GListPtr lpc = NULL;
- GListPtr list = rsc->rsc_location;
+ GList *lpc = NULL;
+ GList *list = rsc->rsc_location;
out->begin_list(out, NULL, NULL, "Locations");
for (lpc = list; lpc != NULL; lpc = lpc->next) {
pe__location_t *cons = lpc->data;
- GListPtr lpc2 = NULL;
+ GList *lpc2 = NULL;
for (lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) {
pe_node_t *node = (pe_node_t *) lpc2->data;
char *score = score2char(node->weight);
out->list_item(out, NULL, "Node %s (score=%s, id=%s)",
node->details->uname, score, cons->id);
free(score);
}
}
out->end_list(out);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("locations-list", "pe_resource_t *")
static int locations_list_xml(pcmk__output_t *out, va_list args) {
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
- GListPtr lpc = NULL;
- GListPtr list = rsc->rsc_location;
+ GList *lpc = NULL;
+ GList *list = rsc->rsc_location;
pcmk__output_xml_create_parent(out, "locations", NULL);
for (lpc = list; lpc != NULL; lpc = lpc->next) {
pe__location_t *cons = lpc->data;
- GListPtr lpc2 = NULL;
+ GList *lpc2 = NULL;
for (lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) {
pe_node_t *node = (pe_node_t *) lpc2->data;
char *score = score2char(node->weight);
pcmk__output_create_xml_node(out, "location",
"host", node->details->uname,
"id", cons->id,
"score", score,
NULL);
free(score);
}
}
pcmk__output_xml_pop_parent(out);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("stacks-constraints", "pe_resource_t *", "pe_working_set_t *", "gboolean")
static int
stacks_and_constraints(pcmk__output_t *out, va_list args) {
pe_resource_t *rsc G_GNUC_UNUSED = va_arg(args, pe_resource_t *);
pe_working_set_t *data_set G_GNUC_UNUSED = va_arg(args, pe_working_set_t *);
gboolean recursive G_GNUC_UNUSED = va_arg(args, gboolean);
- GListPtr lpc = NULL;
- xmlNode *cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS,
- data_set->input);
+ GList *lpc = NULL;
+ xmlNodePtr cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS,
+ data_set->input);
unpack_constraints(cib_constraints, data_set);
// Constraints apply to group/clone, not member/instance
rsc = uber_parent(rsc);
for (lpc = data_set->resources; lpc != NULL; lpc = lpc->next) {
pe_resource_t *r = (pe_resource_t *) lpc->data;
pe__clear_resource_flags(r, pe_rsc_allocating);
}
out->message(out, "colocations-list", rsc, TRUE, recursive);
out->begin_list(out, NULL, NULL, "%s", rsc->id);
out->message(out, "locations-list", rsc);
out->end_list(out);
for (lpc = data_set->resources; lpc != NULL; lpc = lpc->next) {
pe_resource_t *r = (pe_resource_t *) lpc->data;
pe__clear_resource_flags(r, pe_rsc_allocating);
}
out->message(out, "colocations-list", rsc, FALSE, recursive);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("stacks-constraints", "pe_resource_t *", "pe_working_set_t *", "gboolean")
static int
stacks_and_constraints_xml(pcmk__output_t *out, va_list args) {
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
gboolean recursive = va_arg(args, gboolean);
- GListPtr lpc = NULL;
- xmlNode *cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS,
- data_set->input);
+ GList *lpc = NULL;
+ xmlNodePtr cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS,
+ data_set->input);
unpack_constraints(cib_constraints, data_set);
// Constraints apply to group/clone, not member/instance
rsc = uber_parent(rsc);
for (lpc = data_set->resources; lpc != NULL; lpc = lpc->next) {
pe_resource_t *r = (pe_resource_t *) lpc->data;
pe__clear_resource_flags(r, pe_rsc_allocating);
}
pcmk__output_xml_create_parent(out, "constraints", NULL);
out->message(out, "colocations-list", rsc, TRUE, recursive);
pcmk__output_xml_create_parent(out, "resource",
"id", rsc->id,
NULL);
out->message(out, "locations-list", rsc);
pcmk__output_xml_pop_parent(out);
for (lpc = data_set->resources; lpc != NULL; lpc = lpc->next) {
pe_resource_t *r = (pe_resource_t *) lpc->data;
pe__clear_resource_flags(r, pe_rsc_allocating);
}
out->message(out, "colocations-list", rsc, FALSE, recursive);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("health", "char *", "char *", "char *", "char *")
static int
health_text(pcmk__output_t *out, va_list args)
{
char *sys_from = va_arg(args, char *);
char *host_from = va_arg(args, char *);
char *fsa_state = va_arg(args, char *);
char *result = va_arg(args, char *);
if (!out->is_quiet(out)) {
out->info(out, "Status of %s@%s: %s (%s)", crm_str(sys_from),
crm_str(host_from), crm_str(fsa_state), crm_str(result));
} else if (fsa_state != NULL) {
out->info(out, "%s", fsa_state);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("health", "char *", "char *", "char *", "char *")
static int
health_xml(pcmk__output_t *out, va_list args)
{
char *sys_from = va_arg(args, char *);
char *host_from = va_arg(args, char *);
char *fsa_state = va_arg(args, char *);
char *result = va_arg(args, char *);
pcmk__output_create_xml_node(out, crm_str(sys_from),
"node_name", crm_str(host_from),
"state", crm_str(fsa_state),
"result", crm_str(result),
NULL);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("pacemakerd-health", "char *", "char *", "char *")
static int
pacemakerd_health_text(pcmk__output_t *out, va_list args)
{
char *sys_from = va_arg(args, char *);
char *state = va_arg(args, char *);
char *last_updated = va_arg(args, char *);
if (!out->is_quiet(out)) {
out->info(out, "Status of %s: '%s' %s %s", crm_str(sys_from),
crm_str(state), (!pcmk__str_empty(last_updated))?
"last updated":"", crm_str(last_updated));
} else {
out->info(out, "%s", crm_str(state));
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("pacemakerd-health", "char *", "char *", "char *")
static int
pacemakerd_health_xml(pcmk__output_t *out, va_list args)
{
char *sys_from = va_arg(args, char *);
char *state = va_arg(args, char *);
char *last_updated = va_arg(args, char *);
pcmk__output_create_xml_node(out, crm_str(sys_from),
"state", crm_str(state),
"last_updated", crm_str(last_updated),
NULL);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("dc", "char *")
static int
dc_text(pcmk__output_t *out, va_list args)
{
char *dc = va_arg(args, char *);
if (!out->is_quiet(out)) {
out->info(out, "Designated Controller is: %s", crm_str(dc));
} else if (dc != NULL) {
out->info(out, "%s", dc);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("dc", "char *")
static int
dc_xml(pcmk__output_t *out, va_list args)
{
char *dc = va_arg(args, char *);
pcmk__output_create_xml_node(out, "dc",
"node_name", crm_str(dc),
NULL);
return pcmk_rc_ok;
}
-PCMK__OUTPUT_ARGS("crmadmin-node-list", "pcmk__output_t *", "xmlNode *")
+PCMK__OUTPUT_ARGS("crmadmin-node-list", "pcmk__output_t *", "xmlNodePtr")
static int
crmadmin_node_list(pcmk__output_t *out, va_list args)
{
- xmlNode *xml_node = va_arg(args, xmlNode *);
+ xmlNodePtr xml_node = va_arg(args, xmlNodePtr);
int found = 0;
xmlNode *node = NULL;
xmlNode *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node);
gboolean BASH_EXPORT = va_arg(args, gboolean);
out->begin_list(out, NULL, NULL, "nodes");
for (node = first_named_child(nodes, XML_CIB_TAG_NODE); node != NULL;
node = crm_next_same_xml(node)) {
const char *node_type = BASH_EXPORT ? NULL :
crm_element_value(node, XML_ATTR_TYPE);
out->message(out, "crmadmin-node", node_type,
crm_str(crm_element_value(node, XML_ATTR_UNAME)),
crm_str(crm_element_value(node, XML_ATTR_ID)),
BASH_EXPORT);
found++;
}
// @TODO List Pacemaker Remote nodes that don't have a <node> entry
out->end_list(out);
if (found == 0) {
out->info(out, "No nodes configured");
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("crmadmin-node", "char *", "char *", "char *", "gboolean")
static int
crmadmin_node_text(pcmk__output_t *out, va_list args)
{
char *type = va_arg(args, char *);
char *name = va_arg(args, char *);
char *id = va_arg(args, char *);
gboolean BASH_EXPORT = va_arg(args, gboolean);
if (BASH_EXPORT) {
out->info(out, "export %s=%s", crm_str(name), crm_str(id));
} else {
out->info(out, "%s node: %s (%s)", type ? type : "member",
crm_str(name), crm_str(id));
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("crmadmin-node", "char *", "char *", "char *", "gboolean")
static int
crmadmin_node_xml(pcmk__output_t *out, va_list args)
{
char *type = va_arg(args, char *);
char *name = va_arg(args, char *);
char *id = va_arg(args, char *);
pcmk__output_create_xml_node(out, "node",
"type", type ? type : "member",
"name", crm_str(name),
"id", crm_str(id),
NULL);
return pcmk_rc_ok;
}
static pcmk__message_entry_t fmt_functions[] = {
{ "colocations-list", "default", colocations_list },
{ "colocations-list", "xml", colocations_list_xml },
{ "locations-list", "default", locations_list },
{ "locations-list", "xml", locations_list_xml },
{ "stacks-constraints", "default", stacks_and_constraints },
{ "stacks-constraints", "xml", stacks_and_constraints_xml },
{ "health", "default", health_text },
{ "health", "xml", health_xml },
{ "pacemakerd-health", "default", pacemakerd_health_text },
{ "pacemakerd-health", "xml", pacemakerd_health_xml },
{ "dc", "default", dc_text },
{ "dc", "xml", dc_xml },
{ "crmadmin-node-list", "default", crmadmin_node_list },
{ "crmadmin-node", "default", crmadmin_node_text },
{ "crmadmin-node", "xml", crmadmin_node_xml },
{ NULL, NULL, NULL }
};
void
pcmk__register_lib_messages(pcmk__output_t *out) {
pcmk__register_messages(out, fmt_functions);
}
diff --git a/lib/pengine/bundle.c b/lib/pengine/bundle.c
index 543f5dc831..7a175a5766 100644
--- a/lib/pengine/bundle.c
+++ b/lib/pengine/bundle.c
@@ -1,2104 +1,2104 @@
/*
* Copyright 2004-2020 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <ctype.h>
#include <crm/pengine/rules.h>
#include <crm/pengine/status.h>
#include <crm/pengine/internal.h>
#include <crm/msg_xml.h>
#include <crm/common/xml_internal.h>
#include <pe_status_private.h>
#define PE__VARIANT_BUNDLE 1
#include "./variant.h"
static char *
next_ip(const char *last_ip)
{
unsigned int oct1 = 0;
unsigned int oct2 = 0;
unsigned int oct3 = 0;
unsigned int oct4 = 0;
int rc = sscanf(last_ip, "%u.%u.%u.%u", &oct1, &oct2, &oct3, &oct4);
if (rc != 4) {
/*@ TODO check for IPv6 */
return NULL;
} else if (oct3 > 253) {
return NULL;
} else if (oct4 > 253) {
++oct3;
oct4 = 1;
} else {
++oct4;
}
return crm_strdup_printf("%u.%u.%u.%u", oct1, oct2, oct3, oct4);
}
static int
allocate_ip(pe__bundle_variant_data_t *data, pe__bundle_replica_t *replica,
char *buffer, int max)
{
if(data->ip_range_start == NULL) {
return 0;
} else if(data->ip_last) {
replica->ipaddr = next_ip(data->ip_last);
} else {
replica->ipaddr = strdup(data->ip_range_start);
}
data->ip_last = replica->ipaddr;
switch (data->agent_type) {
case PE__CONTAINER_AGENT_DOCKER:
case PE__CONTAINER_AGENT_PODMAN:
if (data->add_host) {
return snprintf(buffer, max, " --add-host=%s-%d:%s",
data->prefix, replica->offset,
replica->ipaddr);
}
case PE__CONTAINER_AGENT_RKT:
return snprintf(buffer, max, " --hosts-entry=%s=%s-%d",
replica->ipaddr, data->prefix, replica->offset);
default: // PE__CONTAINER_AGENT_UNKNOWN
break;
}
return 0;
}
static xmlNode *
create_resource(const char *name, const char *provider, const char *kind)
{
xmlNode *rsc = create_xml_node(NULL, XML_CIB_TAG_RESOURCE);
crm_xml_add(rsc, XML_ATTR_ID, name);
crm_xml_add(rsc, XML_AGENT_ATTR_CLASS, PCMK_RESOURCE_CLASS_OCF);
crm_xml_add(rsc, XML_AGENT_ATTR_PROVIDER, provider);
crm_xml_add(rsc, XML_ATTR_TYPE, kind);
return rsc;
}
/*!
* \internal
* \brief Check whether cluster can manage resource inside container
*
* \param[in] data Container variant data
*
* \return TRUE if networking configuration is acceptable, FALSE otherwise
*
* \note The resource is manageable if an IP range or control port has been
* specified. If a control port is used without an IP range, replicas per
* host must be 1.
*/
static bool
valid_network(pe__bundle_variant_data_t *data)
{
if(data->ip_range_start) {
return TRUE;
}
if(data->control_port) {
if(data->nreplicas_per_host > 1) {
pe_err("Specifying the 'control-port' for %s requires 'replicas-per-host=1'", data->prefix);
data->nreplicas_per_host = 1;
// @TODO to be sure: pe__clear_resource_flags(rsc, pe_rsc_unique);
}
return TRUE;
}
return FALSE;
}
static bool
create_ip_resource(pe_resource_t *parent, pe__bundle_variant_data_t *data,
pe__bundle_replica_t *replica, pe_working_set_t *data_set)
{
if(data->ip_range_start) {
char *id = NULL;
xmlNode *xml_ip = NULL;
xmlNode *xml_obj = NULL;
id = crm_strdup_printf("%s-ip-%s", data->prefix, replica->ipaddr);
crm_xml_sanitize_id(id);
xml_ip = create_resource(id, "heartbeat", "IPaddr2");
free(id);
xml_obj = create_xml_node(xml_ip, XML_TAG_ATTR_SETS);
crm_xml_set_id(xml_obj, "%s-attributes-%d",
data->prefix, replica->offset);
crm_create_nvpair_xml(xml_obj, NULL, "ip", replica->ipaddr);
if(data->host_network) {
crm_create_nvpair_xml(xml_obj, NULL, "nic", data->host_network);
}
if(data->host_netmask) {
crm_create_nvpair_xml(xml_obj, NULL,
"cidr_netmask", data->host_netmask);
} else {
crm_create_nvpair_xml(xml_obj, NULL, "cidr_netmask", "32");
}
xml_obj = create_xml_node(xml_ip, "operations");
crm_create_op_xml(xml_obj, ID(xml_ip), "monitor", "60s", NULL);
// TODO: Other ops? Timeouts and intervals from underlying resource?
if (!common_unpack(xml_ip, &replica->ip, parent, data_set)) {
return FALSE;
}
parent->children = g_list_append(parent->children, replica->ip);
}
return TRUE;
}
static bool
create_docker_resource(pe_resource_t *parent, pe__bundle_variant_data_t *data,
pe__bundle_replica_t *replica,
pe_working_set_t *data_set)
{
int offset = 0, max = 4096;
char *buffer = calloc(1, max+1);
int doffset = 0, dmax = 1024;
char *dbuffer = calloc(1, dmax+1);
char *id = NULL;
xmlNode *xml_container = NULL;
xmlNode *xml_obj = NULL;
id = crm_strdup_printf("%s-docker-%d", data->prefix, replica->offset);
crm_xml_sanitize_id(id);
xml_container = create_resource(id, "heartbeat",
PE__CONTAINER_AGENT_DOCKER_S);
free(id);
xml_obj = create_xml_node(xml_container, XML_TAG_ATTR_SETS);
crm_xml_set_id(xml_obj, "%s-attributes-%d",
data->prefix, replica->offset);
crm_create_nvpair_xml(xml_obj, NULL, "image", data->image);
crm_create_nvpair_xml(xml_obj, NULL, "allow_pull", XML_BOOLEAN_TRUE);
crm_create_nvpair_xml(xml_obj, NULL, "force_kill", XML_BOOLEAN_FALSE);
crm_create_nvpair_xml(xml_obj, NULL, "reuse", XML_BOOLEAN_FALSE);
offset += snprintf(buffer+offset, max-offset, " --restart=no");
/* Set a container hostname only if we have an IP to map it to.
* The user can set -h or --uts=host themselves if they want a nicer
* name for logs, but this makes applications happy who need their
* hostname to match the IP they bind to.
*/
if (data->ip_range_start != NULL) {
offset += snprintf(buffer+offset, max-offset, " -h %s-%d",
data->prefix, replica->offset);
}
offset += snprintf(buffer+offset, max-offset, " -e PCMK_stderr=1");
if (data->container_network) {
#if 0
offset += snprintf(buffer+offset, max-offset, " --link-local-ip=%s",
replica->ipaddr);
#endif
offset += snprintf(buffer+offset, max-offset, " --net=%s",
data->container_network);
}
if(data->control_port) {
offset += snprintf(buffer+offset, max-offset, " -e PCMK_remote_port=%s", data->control_port);
} else {
offset += snprintf(buffer+offset, max-offset, " -e PCMK_remote_port=%d", DEFAULT_REMOTE_PORT);
}
for(GListPtr pIter = data->mounts; pIter != NULL; pIter = pIter->next) {
pe__bundle_mount_t *mount = pIter->data;
if (pcmk_is_set(mount->flags, pe__bundle_mount_subdir)) {
char *source = crm_strdup_printf(
"%s/%s-%d", mount->source, data->prefix, replica->offset);
if(doffset > 0) {
doffset += snprintf(dbuffer+doffset, dmax-doffset, ",");
}
doffset += snprintf(dbuffer+doffset, dmax-doffset, "%s", source);
offset += snprintf(buffer+offset, max-offset, " -v %s:%s", source, mount->target);
free(source);
} else {
offset += snprintf(buffer+offset, max-offset, " -v %s:%s", mount->source, mount->target);
}
if(mount->options) {
offset += snprintf(buffer+offset, max-offset, ":%s", mount->options);
}
}
for(GListPtr pIter = data->ports; pIter != NULL; pIter = pIter->next) {
pe__bundle_port_t *port = pIter->data;
if (replica->ipaddr) {
offset += snprintf(buffer+offset, max-offset, " -p %s:%s:%s",
replica->ipaddr, port->source,
port->target);
} else if(!pcmk__str_eq(data->container_network, "host", pcmk__str_casei)) {
// No need to do port mapping if net=host
offset += snprintf(buffer+offset, max-offset, " -p %s:%s", port->source, port->target);
}
}
if (data->launcher_options) {
offset += snprintf(buffer+offset, max-offset, " %s",
data->launcher_options);
}
if (data->container_host_options) {
offset += snprintf(buffer + offset, max - offset, " %s",
data->container_host_options);
}
crm_create_nvpair_xml(xml_obj, NULL, "run_opts", buffer);
free(buffer);
crm_create_nvpair_xml(xml_obj, NULL, "mount_points", dbuffer);
free(dbuffer);
if (replica->child) {
if (data->container_command) {
crm_create_nvpair_xml(xml_obj, NULL,
"run_cmd", data->container_command);
} else {
crm_create_nvpair_xml(xml_obj, NULL,
"run_cmd", SBIN_DIR "/pacemaker-remoted");
}
/* TODO: Allow users to specify their own?
*
* We just want to know if the container is alive, we'll
* monitor the child independently
*/
crm_create_nvpair_xml(xml_obj, NULL, "monitor_cmd", "/bin/true");
/* } else if(child && data->untrusted) {
* Support this use-case?
*
* The ability to have resources started/stopped by us, but
* unable to set attributes, etc.
*
* Arguably better to control API access this with ACLs like
* "normal" remote nodes
*
* crm_create_nvpair_xml(xml_obj, NULL,
* "run_cmd",
* "/usr/libexec/pacemaker/pacemaker-execd");
* crm_create_nvpair_xml(xml_obj, NULL, "monitor_cmd",
* "/usr/libexec/pacemaker/lrmd_internal_ctl -c poke");
*/
} else {
if (data->container_command) {
crm_create_nvpair_xml(xml_obj, NULL,
"run_cmd", data->container_command);
}
/* TODO: Allow users to specify their own?
*
* We don't know what's in the container, so we just want
* to know if it is alive
*/
crm_create_nvpair_xml(xml_obj, NULL, "monitor_cmd", "/bin/true");
}
xml_obj = create_xml_node(xml_container, "operations");
crm_create_op_xml(xml_obj, ID(xml_container), "monitor", "60s", NULL);
// TODO: Other ops? Timeouts and intervals from underlying resource?
if (!common_unpack(xml_container, &replica->container, parent, data_set)) {
return FALSE;
}
parent->children = g_list_append(parent->children, replica->container);
return TRUE;
}
static bool
create_podman_resource(pe_resource_t *parent, pe__bundle_variant_data_t *data,
pe__bundle_replica_t *replica,
pe_working_set_t *data_set)
{
int offset = 0, max = 4096;
char *buffer = calloc(1, max+1);
int doffset = 0, dmax = 1024;
char *dbuffer = calloc(1, dmax+1);
char *id = NULL;
xmlNode *xml_container = NULL;
xmlNode *xml_obj = NULL;
id = crm_strdup_printf("%s-podman-%d", data->prefix, replica->offset);
crm_xml_sanitize_id(id);
xml_container = create_resource(id, "heartbeat",
PE__CONTAINER_AGENT_PODMAN_S);
free(id);
xml_obj = create_xml_node(xml_container, XML_TAG_ATTR_SETS);
crm_xml_set_id(xml_obj, "%s-attributes-%d",
data->prefix, replica->offset);
crm_create_nvpair_xml(xml_obj, NULL, "image", data->image);
crm_create_nvpair_xml(xml_obj, NULL, "allow_pull", XML_BOOLEAN_TRUE);
crm_create_nvpair_xml(xml_obj, NULL, "force_kill", XML_BOOLEAN_FALSE);
crm_create_nvpair_xml(xml_obj, NULL, "reuse", XML_BOOLEAN_FALSE);
// FIXME: (bandini 2018-08) podman has no restart policies
//offset += snprintf(buffer+offset, max-offset, " --restart=no");
/* Set a container hostname only if we have an IP to map it to.
* The user can set -h or --uts=host themselves if they want a nicer
* name for logs, but this makes applications happy who need their
* hostname to match the IP they bind to.
*/
if (data->ip_range_start != NULL) {
offset += snprintf(buffer+offset, max-offset, " -h %s-%d",
data->prefix, replica->offset);
}
offset += snprintf(buffer+offset, max-offset, " -e PCMK_stderr=1");
if (data->container_network) {
#if 0
// podman has no support for --link-local-ip
offset += snprintf(buffer+offset, max-offset, " --link-local-ip=%s",
replica->ipaddr);
#endif
offset += snprintf(buffer+offset, max-offset, " --net=%s",
data->container_network);
}
if(data->control_port) {
offset += snprintf(buffer+offset, max-offset, " -e PCMK_remote_port=%s", data->control_port);
} else {
offset += snprintf(buffer+offset, max-offset, " -e PCMK_remote_port=%d", DEFAULT_REMOTE_PORT);
}
for(GListPtr pIter = data->mounts; pIter != NULL; pIter = pIter->next) {
pe__bundle_mount_t *mount = pIter->data;
if (pcmk_is_set(mount->flags, pe__bundle_mount_subdir)) {
char *source = crm_strdup_printf(
"%s/%s-%d", mount->source, data->prefix, replica->offset);
if(doffset > 0) {
doffset += snprintf(dbuffer+doffset, dmax-doffset, ",");
}
doffset += snprintf(dbuffer+doffset, dmax-doffset, "%s", source);
offset += snprintf(buffer+offset, max-offset, " -v %s:%s", source, mount->target);
free(source);
} else {
offset += snprintf(buffer+offset, max-offset, " -v %s:%s", mount->source, mount->target);
}
if(mount->options) {
offset += snprintf(buffer+offset, max-offset, ":%s", mount->options);
}
}
for(GListPtr pIter = data->ports; pIter != NULL; pIter = pIter->next) {
pe__bundle_port_t *port = pIter->data;
if (replica->ipaddr) {
offset += snprintf(buffer+offset, max-offset, " -p %s:%s:%s",
replica->ipaddr, port->source,
port->target);
} else if(!pcmk__str_eq(data->container_network, "host", pcmk__str_casei)) {
// No need to do port mapping if net=host
offset += snprintf(buffer+offset, max-offset, " -p %s:%s", port->source, port->target);
}
}
if (data->launcher_options) {
offset += snprintf(buffer+offset, max-offset, " %s",
data->launcher_options);
}
if (data->container_host_options) {
offset += snprintf(buffer + offset, max - offset, " %s",
data->container_host_options);
}
crm_create_nvpair_xml(xml_obj, NULL, "run_opts", buffer);
free(buffer);
crm_create_nvpair_xml(xml_obj, NULL, "mount_points", dbuffer);
free(dbuffer);
if (replica->child) {
if (data->container_command) {
crm_create_nvpair_xml(xml_obj, NULL,
"run_cmd", data->container_command);
} else {
crm_create_nvpair_xml(xml_obj, NULL,
"run_cmd", SBIN_DIR "/pacemaker-remoted");
}
/* TODO: Allow users to specify their own?
*
* We just want to know if the container is alive, we'll
* monitor the child independently
*/
crm_create_nvpair_xml(xml_obj, NULL, "monitor_cmd", "/bin/true");
/* } else if(child && data->untrusted) {
* Support this use-case?
*
* The ability to have resources started/stopped by us, but
* unable to set attributes, etc.
*
* Arguably better to control API access this with ACLs like
* "normal" remote nodes
*
* crm_create_nvpair_xml(xml_obj, NULL,
* "run_cmd",
* "/usr/libexec/pacemaker/pacemaker-execd");
* crm_create_nvpair_xml(xml_obj, NULL, "monitor_cmd",
* "/usr/libexec/pacemaker/lrmd_internal_ctl -c poke");
*/
} else {
if (data->container_command) {
crm_create_nvpair_xml(xml_obj, NULL,
"run_cmd", data->container_command);
}
/* TODO: Allow users to specify their own?
*
* We don't know what's in the container, so we just want
* to know if it is alive
*/
crm_create_nvpair_xml(xml_obj, NULL, "monitor_cmd", "/bin/true");
}
xml_obj = create_xml_node(xml_container, "operations");
crm_create_op_xml(xml_obj, ID(xml_container), "monitor", "60s", NULL);
// TODO: Other ops? Timeouts and intervals from underlying resource?
if (!common_unpack(xml_container, &replica->container, parent,
data_set)) {
return FALSE;
}
parent->children = g_list_append(parent->children, replica->container);
return TRUE;
}
static bool
create_rkt_resource(pe_resource_t *parent, pe__bundle_variant_data_t *data,
pe__bundle_replica_t *replica, pe_working_set_t *data_set)
{
int offset = 0, max = 4096;
char *buffer = calloc(1, max+1);
int doffset = 0, dmax = 1024;
char *dbuffer = calloc(1, dmax+1);
char *id = NULL;
xmlNode *xml_container = NULL;
xmlNode *xml_obj = NULL;
int volid = 0;
id = crm_strdup_printf("%s-rkt-%d", data->prefix, replica->offset);
crm_xml_sanitize_id(id);
xml_container = create_resource(id, "heartbeat",
PE__CONTAINER_AGENT_RKT_S);
free(id);
xml_obj = create_xml_node(xml_container, XML_TAG_ATTR_SETS);
crm_xml_set_id(xml_obj, "%s-attributes-%d",
data->prefix, replica->offset);
crm_create_nvpair_xml(xml_obj, NULL, "image", data->image);
crm_create_nvpair_xml(xml_obj, NULL, "allow_pull", "true");
crm_create_nvpair_xml(xml_obj, NULL, "force_kill", "false");
crm_create_nvpair_xml(xml_obj, NULL, "reuse", "false");
/* Set a container hostname only if we have an IP to map it to.
* The user can set -h or --uts=host themselves if they want a nicer
* name for logs, but this makes applications happy who need their
* hostname to match the IP they bind to.
*/
if (data->ip_range_start != NULL) {
offset += snprintf(buffer+offset, max-offset, " --hostname=%s-%d",
data->prefix, replica->offset);
}
offset += snprintf(buffer+offset, max-offset, " --environment=PCMK_stderr=1");
if (data->container_network) {
#if 0
offset += snprintf(buffer+offset, max-offset, " --link-local-ip=%s",
replica->ipaddr);
#endif
offset += snprintf(buffer+offset, max-offset, " --net=%s",
data->container_network);
}
if(data->control_port) {
offset += snprintf(buffer+offset, max-offset, " --environment=PCMK_remote_port=%s", data->control_port);
} else {
offset += snprintf(buffer+offset, max-offset, " --environment=PCMK_remote_port=%d", DEFAULT_REMOTE_PORT);
}
for(GListPtr pIter = data->mounts; pIter != NULL; pIter = pIter->next) {
pe__bundle_mount_t *mount = pIter->data;
if (pcmk_is_set(mount->flags, pe__bundle_mount_subdir)) {
char *source = crm_strdup_printf(
"%s/%s-%d", mount->source, data->prefix, replica->offset);
if(doffset > 0) {
doffset += snprintf(dbuffer+doffset, dmax-doffset, ",");
}
doffset += snprintf(dbuffer+doffset, dmax-doffset, "%s", source);
offset += snprintf(buffer+offset, max-offset, " --volume vol%d,kind=host,source=%s", volid, source);
if(mount->options) {
offset += snprintf(buffer+offset, max-offset, ",%s", mount->options);
}
offset += snprintf(buffer+offset, max-offset, " --mount volume=vol%d,target=%s", volid, mount->target);
free(source);
} else {
offset += snprintf(buffer+offset, max-offset, " --volume vol%d,kind=host,source=%s", volid, mount->source);
if(mount->options) {
offset += snprintf(buffer+offset, max-offset, ",%s", mount->options);
}
offset += snprintf(buffer+offset, max-offset, " --mount volume=vol%d,target=%s", volid, mount->target);
}
volid++;
}
for(GListPtr pIter = data->ports; pIter != NULL; pIter = pIter->next) {
pe__bundle_port_t *port = pIter->data;
if (replica->ipaddr) {
offset += snprintf(buffer+offset, max-offset,
" --port=%s:%s:%s", port->target,
replica->ipaddr, port->source);
} else {
offset += snprintf(buffer+offset, max-offset, " --port=%s:%s", port->target, port->source);
}
}
if (data->launcher_options) {
offset += snprintf(buffer+offset, max-offset, " %s",
data->launcher_options);
}
if (data->container_host_options) {
offset += snprintf(buffer + offset, max - offset, " %s",
data->container_host_options);
}
crm_create_nvpair_xml(xml_obj, NULL, "run_opts", buffer);
free(buffer);
crm_create_nvpair_xml(xml_obj, NULL, "mount_points", dbuffer);
free(dbuffer);
if (replica->child) {
if (data->container_command) {
crm_create_nvpair_xml(xml_obj, NULL, "run_cmd",
data->container_command);
} else {
crm_create_nvpair_xml(xml_obj, NULL, "run_cmd",
SBIN_DIR "/pacemaker-remoted");
}
/* TODO: Allow users to specify their own?
*
* We just want to know if the container is alive, we'll
* monitor the child independently
*/
crm_create_nvpair_xml(xml_obj, NULL, "monitor_cmd", "/bin/true");
/* } else if(child && data->untrusted) {
* Support this use-case?
*
* The ability to have resources started/stopped by us, but
* unable to set attributes, etc.
*
* Arguably better to control API access this with ACLs like
* "normal" remote nodes
*
* crm_create_nvpair_xml(xml_obj, NULL,
* "run_cmd",
* "/usr/libexec/pacemaker/pacemaker-execd");
* crm_create_nvpair_xml(xml_obj, NULL, "monitor_cmd",
* "/usr/libexec/pacemaker/lrmd_internal_ctl -c poke");
*/
} else {
if (data->container_command) {
crm_create_nvpair_xml(xml_obj, NULL, "run_cmd",
data->container_command);
}
/* TODO: Allow users to specify their own?
*
* We don't know what's in the container, so we just want
* to know if it is alive
*/
crm_create_nvpair_xml(xml_obj, NULL, "monitor_cmd", "/bin/true");
}
xml_obj = create_xml_node(xml_container, "operations");
crm_create_op_xml(xml_obj, ID(xml_container), "monitor", "60s", NULL);
// TODO: Other ops? Timeouts and intervals from underlying resource?
if (!common_unpack(xml_container, &replica->container, parent, data_set)) {
return FALSE;
}
parent->children = g_list_append(parent->children, replica->container);
return TRUE;
}
/*!
* \brief Ban a node from a resource's (and its children's) allowed nodes list
*
* \param[in,out] rsc Resource to modify
* \param[in] uname Name of node to ban
*/
static void
disallow_node(pe_resource_t *rsc, const char *uname)
{
gpointer match = g_hash_table_lookup(rsc->allowed_nodes, uname);
if (match) {
((pe_node_t *) match)->weight = -INFINITY;
((pe_node_t *) match)->rsc_discover_mode = pe_discover_never;
}
if (rsc->children) {
GListPtr child;
for (child = rsc->children; child != NULL; child = child->next) {
disallow_node((pe_resource_t *) (child->data), uname);
}
}
}
static bool
create_remote_resource(pe_resource_t *parent, pe__bundle_variant_data_t *data,
pe__bundle_replica_t *replica,
pe_working_set_t *data_set)
{
if (replica->child && valid_network(data)) {
GHashTableIter gIter;
GListPtr rsc_iter = NULL;
pe_node_t *node = NULL;
xmlNode *xml_remote = NULL;
char *id = crm_strdup_printf("%s-%d", data->prefix, replica->offset);
char *port_s = NULL;
const char *uname = NULL;
const char *connect_name = NULL;
if (pe_find_resource(data_set->resources, id) != NULL) {
free(id);
// The biggest hammer we have
id = crm_strdup_printf("pcmk-internal-%s-remote-%d",
replica->child->id, replica->offset);
//@TODO return false instead of asserting?
CRM_ASSERT(pe_find_resource(data_set->resources, id) == NULL);
}
/* REMOTE_CONTAINER_HACK: Using "#uname" as the server name when the
* connection does not have its own IP is a magic string that we use to
* support nested remotes (i.e. a bundle running on a remote node).
*/
connect_name = (replica->ipaddr? replica->ipaddr : "#uname");
if (data->control_port == NULL) {
port_s = crm_itoa(DEFAULT_REMOTE_PORT);
}
/* This sets replica->container as replica->remote's container, which is
* similar to what happens with guest nodes. This is how the scheduler
* knows that the bundle node is fenced by recovering the container, and
* that remote should be ordered relative to the container.
*/
xml_remote = pe_create_remote_xml(NULL, id, replica->container->id,
NULL, NULL, NULL,
connect_name, (data->control_port?
data->control_port : port_s));
free(port_s);
/* Abandon our created ID, and pull the copy from the XML, because we
* need something that will get freed during data set cleanup to use as
* the node ID and uname.
*/
free(id);
id = NULL;
uname = ID(xml_remote);
/* Ensure a node has been created for the guest (it may have already
* been, if it has a permanent node attribute), and ensure its weight is
* -INFINITY so no other resources can run on it.
*/
node = pe_find_node(data_set->nodes, uname);
if (node == NULL) {
node = pe_create_node(uname, uname, "remote", "-INFINITY",
data_set);
} else {
node->weight = -INFINITY;
}
node->rsc_discover_mode = pe_discover_never;
/* unpack_remote_nodes() ensures that each remote node and guest node
* has a pe_node_t entry. Ideally, it would do the same for bundle nodes.
* Unfortunately, a bundle has to be mostly unpacked before it's obvious
* what nodes will be needed, so we do it just above.
*
* Worse, that means that the node may have been utilized while
* unpacking other resources, without our weight correction. The most
* likely place for this to happen is when common_unpack() calls
* resource_location() to set a default score in symmetric clusters.
* This adds a node *copy* to each resource's allowed nodes, and these
* copies will have the wrong weight.
*
* As a hacky workaround, fix those copies here.
*
* @TODO Possible alternative: ensure bundles are unpacked before other
* resources, so the weight is correct before any copies are made.
*/
for (rsc_iter = data_set->resources; rsc_iter; rsc_iter = rsc_iter->next) {
disallow_node((pe_resource_t *) (rsc_iter->data), uname);
}
replica->node = pe__copy_node(node);
replica->node->weight = 500;
replica->node->rsc_discover_mode = pe_discover_exclusive;
/* Ensure the node shows up as allowed and with the correct discovery set */
if (replica->child->allowed_nodes != NULL) {
g_hash_table_destroy(replica->child->allowed_nodes);
}
replica->child->allowed_nodes = g_hash_table_new_full(crm_str_hash,
g_str_equal,
NULL, free);
g_hash_table_insert(replica->child->allowed_nodes,
(gpointer) replica->node->details->id,
pe__copy_node(replica->node));
{
pe_node_t *copy = pe__copy_node(replica->node);
copy->weight = -INFINITY;
g_hash_table_insert(replica->child->parent->allowed_nodes,
(gpointer) replica->node->details->id, copy);
}
if (!common_unpack(xml_remote, &replica->remote, parent, data_set)) {
return FALSE;
}
g_hash_table_iter_init(&gIter, replica->remote->allowed_nodes);
while (g_hash_table_iter_next(&gIter, NULL, (void **)&node)) {
if (pe__is_guest_or_remote_node(node)) {
/* Remote resources can only run on 'normal' cluster node */
node->weight = -INFINITY;
}
}
replica->node->details->remote_rsc = replica->remote;
// Ensure pe__is_guest_node() functions correctly immediately
replica->remote->container = replica->container;
/* A bundle's #kind is closer to "container" (guest node) than the
* "remote" set by pe_create_node().
*/
g_hash_table_insert(replica->node->details->attrs,
strdup(CRM_ATTR_KIND), strdup("container"));
/* One effect of this is that setup_container() will add
* replica->remote to replica->container's fillers, which will make
* pe__resource_contains_guest_node() true for replica->container.
*
* replica->child does NOT get added to replica->container's fillers.
* The only noticeable effect if it did would be for its fail count to
* be taken into account when checking replica->container's migration
* threshold.
*/
parent->children = g_list_append(parent->children, replica->remote);
}
return TRUE;
}
static bool
create_container(pe_resource_t *parent, pe__bundle_variant_data_t *data,
pe__bundle_replica_t *replica, pe_working_set_t *data_set)
{
switch (data->agent_type) {
case PE__CONTAINER_AGENT_DOCKER:
if (!create_docker_resource(parent, data, replica, data_set)) {
return FALSE;
}
break;
case PE__CONTAINER_AGENT_PODMAN:
if (!create_podman_resource(parent, data, replica, data_set)) {
return FALSE;
}
break;
case PE__CONTAINER_AGENT_RKT:
if (!create_rkt_resource(parent, data, replica, data_set)) {
return FALSE;
}
break;
default: // PE__CONTAINER_AGENT_UNKNOWN
return FALSE;
}
if (create_ip_resource(parent, data, replica, data_set) == FALSE) {
return FALSE;
}
if(create_remote_resource(parent, data, replica, data_set) == FALSE) {
return FALSE;
}
if (replica->child && replica->ipaddr) {
add_hash_param(replica->child->meta, "external-ip", replica->ipaddr);
}
if (replica->remote) {
/*
* Allow the remote connection resource to be allocated to a
* different node than the one on which the container is active.
*
* This makes it possible to have Pacemaker Remote nodes running
* containers with pacemaker-remoted inside in order to start
* services inside those containers.
*/
pe__set_resource_flags(replica->remote, pe_rsc_allow_remote_remotes);
}
return TRUE;
}
static void
mount_add(pe__bundle_variant_data_t *bundle_data, const char *source,
const char *target, const char *options, uint32_t flags)
{
pe__bundle_mount_t *mount = calloc(1, sizeof(pe__bundle_mount_t));
mount->source = strdup(source);
mount->target = strdup(target);
if (options) {
mount->options = strdup(options);
}
mount->flags = flags;
bundle_data->mounts = g_list_append(bundle_data->mounts, mount);
}
static void
mount_free(pe__bundle_mount_t *mount)
{
free(mount->source);
free(mount->target);
free(mount->options);
free(mount);
}
static void
port_free(pe__bundle_port_t *port)
{
free(port->source);
free(port->target);
free(port);
}
static pe__bundle_replica_t *
replica_for_remote(pe_resource_t *remote)
{
pe_resource_t *top = remote;
pe__bundle_variant_data_t *bundle_data = NULL;
if (top == NULL) {
return NULL;
}
while (top->parent != NULL) {
top = top->parent;
}
get_bundle_variant_data(bundle_data, top);
for (GList *gIter = bundle_data->replicas; gIter != NULL;
gIter = gIter->next) {
pe__bundle_replica_t *replica = gIter->data;
if (replica->remote == remote) {
return replica;
}
}
CRM_LOG_ASSERT(FALSE);
return NULL;
}
bool
pe__bundle_needs_remote_name(pe_resource_t *rsc)
{
const char *value;
if (rsc == NULL) {
return false;
}
value = g_hash_table_lookup(rsc->parameters, XML_RSC_ATTR_REMOTE_RA_ADDR);
return pcmk__str_eq(value, "#uname", pcmk__str_casei)
&& xml_contains_remote_node(rsc->xml);
}
const char *
pe__add_bundle_remote_name(pe_resource_t *rsc, xmlNode *xml, const char *field)
{
// REMOTE_CONTAINER_HACK: Allow remote nodes that start containers with pacemaker remote inside
pe_node_t *node = NULL;
pe__bundle_replica_t *replica = NULL;
if (!pe__bundle_needs_remote_name(rsc)) {
return NULL;
}
replica = replica_for_remote(rsc);
if (replica == NULL) {
return NULL;
}
node = replica->container->allocated_to;
if (node == NULL) {
/* If it won't be running anywhere after the
* transition, go with where it's running now.
*/
node = pe__current_node(replica->container);
}
if(node == NULL) {
crm_trace("Cannot determine address for bundle connection %s", rsc->id);
return NULL;
}
crm_trace("Setting address for bundle connection %s to bundle host %s",
rsc->id, node->details->uname);
if(xml != NULL && field != NULL) {
crm_xml_add(xml, field, node->details->uname);
}
return node->details->uname;
}
#define pe__set_bundle_mount_flags(mount_xml, flags, flags_to_set) do { \
flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE, \
"Bundle mount", ID(mount_xml), flags, \
(flags_to_set), #flags_to_set); \
} while (0)
gboolean
pe__unpack_bundle(pe_resource_t *rsc, pe_working_set_t *data_set)
{
const char *value = NULL;
xmlNode *xml_obj = NULL;
xmlNode *xml_resource = NULL;
pe__bundle_variant_data_t *bundle_data = NULL;
bool need_log_mount = TRUE;
CRM_ASSERT(rsc != NULL);
pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
bundle_data = calloc(1, sizeof(pe__bundle_variant_data_t));
rsc->variant_opaque = bundle_data;
bundle_data->prefix = strdup(rsc->id);
xml_obj = first_named_child(rsc->xml, PE__CONTAINER_AGENT_DOCKER_S);
if (xml_obj != NULL) {
bundle_data->agent_type = PE__CONTAINER_AGENT_DOCKER;
} else {
xml_obj = first_named_child(rsc->xml, PE__CONTAINER_AGENT_RKT_S);
if (xml_obj != NULL) {
bundle_data->agent_type = PE__CONTAINER_AGENT_RKT;
} else {
xml_obj = first_named_child(rsc->xml, PE__CONTAINER_AGENT_PODMAN_S);
if (xml_obj != NULL) {
bundle_data->agent_type = PE__CONTAINER_AGENT_PODMAN;
} else {
return FALSE;
}
}
}
value = crm_element_value(xml_obj, XML_RSC_ATTR_PROMOTED_MAX);
if (value == NULL) {
// @COMPAT deprecated since 2.0.0
value = crm_element_value(xml_obj, "masters");
}
bundle_data->promoted_max = crm_parse_int(value, "0");
if (bundle_data->promoted_max < 0) {
pe_err("%s for %s must be nonnegative integer, using 0",
XML_RSC_ATTR_PROMOTED_MAX, rsc->id);
bundle_data->promoted_max = 0;
}
value = crm_element_value(xml_obj, "replicas");
if ((value == NULL) && bundle_data->promoted_max) {
bundle_data->nreplicas = bundle_data->promoted_max;
} else {
bundle_data->nreplicas = crm_parse_int(value, "1");
}
if (bundle_data->nreplicas < 1) {
pe_err("'replicas' for %s must be positive integer, using 1", rsc->id);
bundle_data->nreplicas = 1;
}
/*
* Communication between containers on the same host via the
* floating IPs only works if the container is started with:
* --userland-proxy=false --ip-masq=false
*/
value = crm_element_value(xml_obj, "replicas-per-host");
bundle_data->nreplicas_per_host = crm_parse_int(value, "1");
if (bundle_data->nreplicas_per_host < 1) {
pe_err("'replicas-per-host' for %s must be positive integer, using 1",
rsc->id);
bundle_data->nreplicas_per_host = 1;
}
if (bundle_data->nreplicas_per_host == 1) {
pe__clear_resource_flags(rsc, pe_rsc_unique);
}
bundle_data->container_command = crm_element_value_copy(xml_obj, "run-command");
bundle_data->launcher_options = crm_element_value_copy(xml_obj, "options");
bundle_data->image = crm_element_value_copy(xml_obj, "image");
bundle_data->container_network = crm_element_value_copy(xml_obj, "network");
xml_obj = first_named_child(rsc->xml, "network");
if(xml_obj) {
bundle_data->ip_range_start = crm_element_value_copy(xml_obj, "ip-range-start");
bundle_data->host_netmask = crm_element_value_copy(xml_obj, "host-netmask");
bundle_data->host_network = crm_element_value_copy(xml_obj, "host-interface");
bundle_data->control_port = crm_element_value_copy(xml_obj, "control-port");
value = crm_element_value(xml_obj, "add-host");
if (crm_str_to_boolean(value, &bundle_data->add_host) != 1) {
bundle_data->add_host = TRUE;
}
for (xmlNode *xml_child = pcmk__xe_first_child(xml_obj); xml_child != NULL;
xml_child = pcmk__xe_next(xml_child)) {
pe__bundle_port_t *port = calloc(1, sizeof(pe__bundle_port_t));
port->source = crm_element_value_copy(xml_child, "port");
if(port->source == NULL) {
port->source = crm_element_value_copy(xml_child, "range");
} else {
port->target = crm_element_value_copy(xml_child, "internal-port");
}
if(port->source != NULL && strlen(port->source) > 0) {
if(port->target == NULL) {
port->target = strdup(port->source);
}
bundle_data->ports = g_list_append(bundle_data->ports, port);
} else {
pe_err("Invalid port directive %s", ID(xml_child));
port_free(port);
}
}
}
xml_obj = first_named_child(rsc->xml, "storage");
for (xmlNode *xml_child = pcmk__xe_first_child(xml_obj); xml_child != NULL;
xml_child = pcmk__xe_next(xml_child)) {
const char *source = crm_element_value(xml_child, "source-dir");
const char *target = crm_element_value(xml_child, "target-dir");
const char *options = crm_element_value(xml_child, "options");
int flags = pe__bundle_mount_none;
if (source == NULL) {
source = crm_element_value(xml_child, "source-dir-root");
pe__set_bundle_mount_flags(xml_child, flags,
pe__bundle_mount_subdir);
}
if (source && target) {
mount_add(bundle_data, source, target, options, flags);
if (strcmp(target, "/var/log") == 0) {
need_log_mount = FALSE;
}
} else {
pe_err("Invalid mount directive %s", ID(xml_child));
}
}
xml_obj = first_named_child(rsc->xml, "primitive");
if (xml_obj && valid_network(bundle_data)) {
char *value = NULL;
xmlNode *xml_set = NULL;
xml_resource = create_xml_node(NULL, XML_CIB_TAG_INCARNATION);
/* @COMPAT We no longer use the <master> tag, but we need to keep it as
* part of the resource name, so that bundles don't restart in a rolling
* upgrade. (It also avoids needing to change regression tests.)
*/
crm_xml_set_id(xml_resource, "%s-%s", bundle_data->prefix,
(bundle_data->promoted_max? "master"
: (const char *)xml_resource->name));
xml_set = create_xml_node(xml_resource, XML_TAG_META_SETS);
crm_xml_set_id(xml_set, "%s-%s-meta", bundle_data->prefix, xml_resource->name);
crm_create_nvpair_xml(xml_set, NULL,
XML_RSC_ATTR_ORDERED, XML_BOOLEAN_TRUE);
value = crm_itoa(bundle_data->nreplicas);
crm_create_nvpair_xml(xml_set, NULL,
XML_RSC_ATTR_INCARNATION_MAX, value);
free(value);
value = crm_itoa(bundle_data->nreplicas_per_host);
crm_create_nvpair_xml(xml_set, NULL,
XML_RSC_ATTR_INCARNATION_NODEMAX, value);
free(value);
crm_create_nvpair_xml(xml_set, NULL, XML_RSC_ATTR_UNIQUE,
pcmk__btoa(bundle_data->nreplicas_per_host > 1));
if (bundle_data->promoted_max) {
crm_create_nvpair_xml(xml_set, NULL,
XML_RSC_ATTR_PROMOTABLE, XML_BOOLEAN_TRUE);
value = crm_itoa(bundle_data->promoted_max);
crm_create_nvpair_xml(xml_set, NULL,
XML_RSC_ATTR_PROMOTED_MAX, value);
free(value);
}
//crm_xml_add(xml_obj, XML_ATTR_ID, bundle_data->prefix);
add_node_copy(xml_resource, xml_obj);
} else if(xml_obj) {
pe_err("Cannot control %s inside %s without either ip-range-start or control-port",
rsc->id, ID(xml_obj));
return FALSE;
}
if(xml_resource) {
int lpc = 0;
GListPtr childIter = NULL;
pe_resource_t *new_rsc = NULL;
pe__bundle_port_t *port = NULL;
int offset = 0, max = 1024;
char *buffer = NULL;
if (common_unpack(xml_resource, &new_rsc, rsc, data_set) == FALSE) {
pe_err("Failed unpacking resource %s", ID(rsc->xml));
if (new_rsc != NULL && new_rsc->fns != NULL) {
new_rsc->fns->free(new_rsc);
}
return FALSE;
}
bundle_data->child = new_rsc;
/* Currently, we always map the default authentication key location
* into the same location inside the container.
*
* Ideally, we would respect the host's PCMK_authkey_location, but:
* - it may be different on different nodes;
* - the actual connection will do extra checking to make sure the key
* file exists and is readable, that we can't do here on the DC
* - tools such as crm_resource and crm_simulate may not have the same
* environment variables as the cluster, causing operation digests to
* differ
*
* Always using the default location inside the container is fine,
* because we control the pacemaker_remote environment, and it avoids
* having to pass another environment variable to the container.
*
* @TODO A better solution may be to have only pacemaker_remote use the
* environment variable, and have the cluster nodes use a new
* cluster option for key location. This would introduce the limitation
* of the location being the same on all cluster nodes, but that's
* reasonable.
*/
mount_add(bundle_data, DEFAULT_REMOTE_KEY_LOCATION,
DEFAULT_REMOTE_KEY_LOCATION, NULL, pe__bundle_mount_none);
if (need_log_mount) {
mount_add(bundle_data, CRM_BUNDLE_DIR, "/var/log", NULL,
pe__bundle_mount_subdir);
}
port = calloc(1, sizeof(pe__bundle_port_t));
if(bundle_data->control_port) {
port->source = strdup(bundle_data->control_port);
} else {
/* If we wanted to respect PCMK_remote_port, we could use
* crm_default_remote_port() here and elsewhere in this file instead
* of DEFAULT_REMOTE_PORT.
*
* However, it gains nothing, since we control both the container
* environment and the connection resource parameters, and the user
* can use a different port if desired by setting control-port.
*/
port->source = crm_itoa(DEFAULT_REMOTE_PORT);
}
port->target = strdup(port->source);
bundle_data->ports = g_list_append(bundle_data->ports, port);
buffer = calloc(1, max+1);
for (childIter = bundle_data->child->children; childIter != NULL;
childIter = childIter->next) {
pe__bundle_replica_t *replica = calloc(1, sizeof(pe__bundle_replica_t));
replica->child = childIter->data;
replica->child->exclusive_discover = TRUE;
replica->offset = lpc++;
// Ensure the child's notify gets set based on the underlying primitive's value
if (pcmk_is_set(replica->child->flags, pe_rsc_notify)) {
pe__set_resource_flags(bundle_data->child, pe_rsc_notify);
}
offset += allocate_ip(bundle_data, replica, buffer+offset,
max-offset);
bundle_data->replicas = g_list_append(bundle_data->replicas,
replica);
bundle_data->attribute_target = g_hash_table_lookup(replica->child->meta,
XML_RSC_ATTR_TARGET);
}
bundle_data->container_host_options = buffer;
if (bundle_data->attribute_target) {
g_hash_table_replace(rsc->meta, strdup(XML_RSC_ATTR_TARGET),
strdup(bundle_data->attribute_target));
g_hash_table_replace(bundle_data->child->meta,
strdup(XML_RSC_ATTR_TARGET),
strdup(bundle_data->attribute_target));
}
} else {
// Just a naked container, no pacemaker-remote
int offset = 0, max = 1024;
char *buffer = calloc(1, max+1);
for (int lpc = 0; lpc < bundle_data->nreplicas; lpc++) {
pe__bundle_replica_t *replica = calloc(1, sizeof(pe__bundle_replica_t));
replica->offset = lpc;
offset += allocate_ip(bundle_data, replica, buffer+offset,
max-offset);
bundle_data->replicas = g_list_append(bundle_data->replicas,
replica);
}
bundle_data->container_host_options = buffer;
}
for (GList *gIter = bundle_data->replicas; gIter != NULL;
gIter = gIter->next) {
pe__bundle_replica_t *replica = gIter->data;
if (!create_container(rsc, bundle_data, replica, data_set)) {
pe_err("Failed unpacking resource %s", rsc->id);
rsc->fns->free(rsc);
return FALSE;
}
}
if (bundle_data->child) {
rsc->children = g_list_append(rsc->children, bundle_data->child);
}
return TRUE;
}
static int
replica_resource_active(pe_resource_t *rsc, gboolean all)
{
if (rsc) {
gboolean child_active = rsc->fns->active(rsc, all);
if (child_active && !all) {
return TRUE;
} else if (!child_active && all) {
return FALSE;
}
}
return -1;
}
gboolean
pe__bundle_active(pe_resource_t *rsc, gboolean all)
{
pe__bundle_variant_data_t *bundle_data = NULL;
GListPtr iter = NULL;
get_bundle_variant_data(bundle_data, rsc);
for (iter = bundle_data->replicas; iter != NULL; iter = iter->next) {
pe__bundle_replica_t *replica = iter->data;
int rsc_active;
rsc_active = replica_resource_active(replica->ip, all);
if (rsc_active >= 0) {
return (gboolean) rsc_active;
}
rsc_active = replica_resource_active(replica->child, all);
if (rsc_active >= 0) {
return (gboolean) rsc_active;
}
rsc_active = replica_resource_active(replica->container, all);
if (rsc_active >= 0) {
return (gboolean) rsc_active;
}
rsc_active = replica_resource_active(replica->remote, all);
if (rsc_active >= 0) {
return (gboolean) rsc_active;
}
}
/* If "all" is TRUE, we've already checked that no resources were inactive,
* so return TRUE; if "all" is FALSE, we didn't find any active resources,
* so return FALSE.
*/
return all;
}
/*!
* \internal
* \brief Find the bundle replica corresponding to a given node
*
* \param[in] bundle Top-level bundle resource
* \param[in] node Node to search for
*
* \return Bundle replica if found, NULL otherwise
*/
pe_resource_t *
pe__find_bundle_replica(const pe_resource_t *bundle, const pe_node_t *node)
{
pe__bundle_variant_data_t *bundle_data = NULL;
CRM_ASSERT(bundle && node);
get_bundle_variant_data(bundle_data, bundle);
for (GList *gIter = bundle_data->replicas; gIter != NULL;
gIter = gIter->next) {
pe__bundle_replica_t *replica = gIter->data;
CRM_ASSERT(replica && replica->node);
if (replica->node->details == node->details) {
return replica->child;
}
}
return NULL;
}
static void
print_rsc_in_list(pe_resource_t *rsc, const char *pre_text, long options,
void *print_data)
{
if (rsc != NULL) {
if (options & pe_print_html) {
status_print("<li>");
}
rsc->fns->print(rsc, pre_text, options, print_data);
if (options & pe_print_html) {
status_print("</li>\n");
}
}
}
static const char*
container_agent_str(enum pe__container_agent t)
{
switch (t) {
case PE__CONTAINER_AGENT_DOCKER: return PE__CONTAINER_AGENT_DOCKER_S;
case PE__CONTAINER_AGENT_RKT: return PE__CONTAINER_AGENT_RKT_S;
case PE__CONTAINER_AGENT_PODMAN: return PE__CONTAINER_AGENT_PODMAN_S;
default: // PE__CONTAINER_AGENT_UNKNOWN
break;
}
return PE__CONTAINER_AGENT_UNKNOWN_S;
}
static void
bundle_print_xml(pe_resource_t *rsc, const char *pre_text, long options,
void *print_data)
{
pe__bundle_variant_data_t *bundle_data = NULL;
char *child_text = NULL;
CRM_CHECK(rsc != NULL, return);
if (pre_text == NULL) {
pre_text = "";
}
child_text = crm_strdup_printf("%s ", pre_text);
get_bundle_variant_data(bundle_data, rsc);
status_print("%s<bundle ", pre_text);
status_print("id=\"%s\" ", rsc->id);
status_print("type=\"%s\" ", container_agent_str(bundle_data->agent_type));
status_print("image=\"%s\" ", bundle_data->image);
status_print("unique=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_unique));
status_print("managed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_managed));
status_print("failed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_failed));
status_print(">\n");
for (GList *gIter = bundle_data->replicas; gIter != NULL;
gIter = gIter->next) {
pe__bundle_replica_t *replica = gIter->data;
CRM_ASSERT(replica);
status_print("%s <replica id=\"%d\">\n", pre_text, replica->offset);
print_rsc_in_list(replica->ip, child_text, options, print_data);
print_rsc_in_list(replica->child, child_text, options, print_data);
print_rsc_in_list(replica->container, child_text, options, print_data);
print_rsc_in_list(replica->remote, child_text, options, print_data);
status_print("%s </replica>\n", pre_text);
}
status_print("%s</bundle>\n", pre_text);
free(child_text);
}
-PCMK__OUTPUT_ARGS("bundle", "unsigned int", "pe_resource_t *", "GListPtr", "GListPtr")
+PCMK__OUTPUT_ARGS("bundle", "unsigned int", "pe_resource_t *", "GList *", "GList *")
int
pe__bundle_xml(pcmk__output_t *out, va_list args)
{
unsigned int options = va_arg(args, unsigned int);
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
- GListPtr only_node = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
pe__bundle_variant_data_t *bundle_data = NULL;
int rc = pcmk_rc_no_output;
gboolean printed_header = FALSE;
gboolean print_everything = TRUE;
CRM_ASSERT(rsc != NULL);
get_bundle_variant_data(bundle_data, rsc);
if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
return rc;
}
print_everything = pcmk__str_in_list(only_rsc, rsc->id);
for (GList *gIter = bundle_data->replicas; gIter != NULL;
gIter = gIter->next) {
pe__bundle_replica_t *replica = gIter->data;
char *id = crm_itoa(replica->offset);
gboolean print_ip, print_child, print_ctnr, print_remote;
CRM_ASSERT(replica);
if (pcmk__rsc_filtered_by_node(replica->container, only_node)) {
continue;
}
print_ip = replica->ip != NULL &&
!replica->ip->fns->is_filtered(replica->ip, only_rsc, print_everything);
print_child = replica->child != NULL &&
!replica->child->fns->is_filtered(replica->child, only_rsc, print_everything);
print_ctnr = !replica->container->fns->is_filtered(replica->container, only_rsc, print_everything);
print_remote = replica->remote != NULL &&
!replica->remote->fns->is_filtered(replica->remote, only_rsc, print_everything);
if (!print_everything && !print_ip && !print_child && !print_ctnr && !print_remote) {
continue;
}
if (!printed_header) {
printed_header = TRUE;
rc = pe__name_and_nvpairs_xml(out, true, "bundle", 6,
"id", rsc->id,
"type", container_agent_str(bundle_data->agent_type),
"image", bundle_data->image,
"unique", pe__rsc_bool_str(rsc, pe_rsc_unique),
"managed", pe__rsc_bool_str(rsc, pe_rsc_managed),
"failed", pe__rsc_bool_str(rsc, pe_rsc_failed));
CRM_ASSERT(rc == pcmk_rc_ok);
}
rc = pe__name_and_nvpairs_xml(out, true, "replica", 1, "id", id);
free(id);
CRM_ASSERT(rc == pcmk_rc_ok);
if (print_ip) {
out->message(out, crm_map_element_name(replica->ip->xml), options,
replica->ip, only_node, only_rsc);
}
if (print_child) {
out->message(out, crm_map_element_name(replica->child->xml), options,
replica->child, only_node, only_rsc);
}
if (print_ctnr) {
out->message(out, crm_map_element_name(replica->container->xml), options,
replica->container, only_node, only_rsc);
}
if (print_remote) {
out->message(out, crm_map_element_name(replica->remote->xml), options,
replica->remote, only_node, only_rsc);
}
pcmk__output_xml_pop_parent(out); // replica
}
if (printed_header) {
pcmk__output_xml_pop_parent(out); // bundle
}
return rc;
}
static void
pe__bundle_replica_output_html(pcmk__output_t *out, pe__bundle_replica_t *replica,
pe_node_t *node, long options)
{
pe_resource_t *rsc = replica->child;
int offset = 0;
char buffer[LINE_MAX];
if(rsc == NULL) {
rsc = replica->container;
}
if (replica->remote) {
offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
rsc_printable_id(replica->remote));
} else {
offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
rsc_printable_id(replica->container));
}
if (replica->ipaddr) {
offset += snprintf(buffer + offset, LINE_MAX - offset, " (%s)",
replica->ipaddr);
}
pe__common_output_html(out, rsc, buffer, node, options);
}
-PCMK__OUTPUT_ARGS("bundle", "unsigned int", "pe_resource_t *", "GListPtr", "GListPtr")
+PCMK__OUTPUT_ARGS("bundle", "unsigned int", "pe_resource_t *", "GList *", "GList *")
int
pe__bundle_html(pcmk__output_t *out, va_list args)
{
unsigned int options = va_arg(args, unsigned int);
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
- GListPtr only_node = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
pe__bundle_variant_data_t *bundle_data = NULL;
char buffer[LINE_MAX];
int rc = pcmk_rc_no_output;
gboolean print_everything = TRUE;
CRM_ASSERT(rsc != NULL);
get_bundle_variant_data(bundle_data, rsc);
if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
return rc;
}
print_everything = pcmk__str_in_list(only_rsc, rsc->id);
for (GList *gIter = bundle_data->replicas; gIter != NULL;
gIter = gIter->next) {
pe__bundle_replica_t *replica = gIter->data;
gboolean print_ip, print_child, print_ctnr, print_remote;
CRM_ASSERT(replica);
if (pcmk__rsc_filtered_by_node(replica->container, only_node)) {
continue;
}
print_ip = replica->ip != NULL &&
!replica->ip->fns->is_filtered(replica->ip, only_rsc, print_everything);
print_child = replica->child != NULL &&
!replica->child->fns->is_filtered(replica->child, only_rsc, print_everything);
print_ctnr = !replica->container->fns->is_filtered(replica->container, only_rsc, print_everything);
print_remote = replica->remote != NULL &&
!replica->remote->fns->is_filtered(replica->remote, only_rsc, print_everything);
if (pcmk_is_set(options, pe_print_implicit) ||
(print_everything == FALSE && (print_ip || print_child || print_ctnr || print_remote))) {
/* The text output messages used below require pe_print_implicit to
* be set to do anything.
*/
unsigned int new_options = options;
if (!pcmk_is_set(options, pe_print_implicit)) {
new_options |= pe_print_implicit;
}
if (rc == pcmk_rc_no_output) {
pcmk__output_create_xml_node(out, "br", NULL);
}
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Container bundle%s: %s [%s]%s%s",
(bundle_data->nreplicas > 1)? " set" : "",
rsc->id, bundle_data->image,
pcmk_is_set(rsc->flags, pe_rsc_unique) ? " (unique)" : "",
pcmk_is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)");
pcmk__output_xml_create_parent(out, "li", NULL);
if (pcmk__list_of_multiple(bundle_data->replicas)) {
snprintf(buffer, LINE_MAX, " Replica[%d]", replica->offset);
xmlNodeSetContent(pcmk__output_xml_peek_parent(out), (pcmkXmlStr) buffer);
}
pcmk__output_create_xml_node(out, "br", NULL);
out->begin_list(out, NULL, NULL, NULL);
if (print_ip) {
out->message(out, crm_map_element_name(replica->ip->xml),
new_options, replica->ip, only_node, only_rsc);
}
if (print_child) {
out->message(out, crm_map_element_name(replica->child->xml),
new_options, replica->child, only_node, only_rsc);
}
if (print_ctnr) {
out->message(out, crm_map_element_name(replica->container->xml),
new_options, replica->container, only_node, only_rsc);
}
if (print_remote) {
out->message(out, crm_map_element_name(replica->remote->xml),
new_options, replica->remote, only_node, only_rsc);
}
out->end_list(out);
} else if (print_everything == FALSE && !(print_ip || print_child || print_ctnr || print_remote)) {
continue;
} else {
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Container bundle%s: %s [%s]%s%s",
(bundle_data->nreplicas > 1)? " set" : "",
rsc->id, bundle_data->image,
pcmk_is_set(rsc->flags, pe_rsc_unique) ? " (unique)" : "",
pcmk_is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)");
pe__bundle_replica_output_html(out, replica, pe__current_node(replica->container),
options);
}
pcmk__output_xml_pop_parent(out);
}
PCMK__OUTPUT_LIST_FOOTER(out, rc);
return rc;
}
static void
pe__bundle_replica_output_text(pcmk__output_t *out, pe__bundle_replica_t *replica,
pe_node_t *node, long options)
{
pe_resource_t *rsc = replica->child;
int offset = 0;
char buffer[LINE_MAX];
if(rsc == NULL) {
rsc = replica->container;
}
if (replica->remote) {
offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
rsc_printable_id(replica->remote));
} else {
offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
rsc_printable_id(replica->container));
}
if (replica->ipaddr) {
offset += snprintf(buffer + offset, LINE_MAX - offset, " (%s)",
replica->ipaddr);
}
pe__common_output_text(out, rsc, buffer, node, options);
}
-PCMK__OUTPUT_ARGS("bundle", "unsigned int", "pe_resource_t *", "GListPtr", "GListPtr")
+PCMK__OUTPUT_ARGS("bundle", "unsigned int", "pe_resource_t *", "GList *", "GList *")
int
pe__bundle_text(pcmk__output_t *out, va_list args)
{
unsigned int options = va_arg(args, unsigned int);
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
- GListPtr only_node = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
pe__bundle_variant_data_t *bundle_data = NULL;
int rc = pcmk_rc_no_output;
gboolean print_everything = TRUE;
get_bundle_variant_data(bundle_data, rsc);
CRM_ASSERT(rsc != NULL);
if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
return rc;
}
print_everything = pcmk__str_in_list(only_rsc, rsc->id);
for (GList *gIter = bundle_data->replicas; gIter != NULL;
gIter = gIter->next) {
pe__bundle_replica_t *replica = gIter->data;
gboolean print_ip, print_child, print_ctnr, print_remote;
CRM_ASSERT(replica);
if (pcmk__rsc_filtered_by_node(replica->container, only_node)) {
continue;
}
print_ip = replica->ip != NULL &&
!replica->ip->fns->is_filtered(replica->ip, only_rsc, print_everything);
print_child = replica->child != NULL &&
!replica->child->fns->is_filtered(replica->child, only_rsc, print_everything);
print_ctnr = !replica->container->fns->is_filtered(replica->container, only_rsc, print_everything);
print_remote = replica->remote != NULL &&
!replica->remote->fns->is_filtered(replica->remote, only_rsc, print_everything);
if (pcmk_is_set(options, pe_print_implicit) ||
(print_everything == FALSE && (print_ip || print_child || print_ctnr || print_remote))) {
/* The text output messages used below require pe_print_implicit to
* be set to do anything.
*/
unsigned int new_options = options;
if (!pcmk_is_set(options, pe_print_implicit)) {
new_options |= pe_print_implicit;
}
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Container bundle%s: %s [%s]%s%s",
(bundle_data->nreplicas > 1)? " set" : "",
rsc->id, bundle_data->image,
pcmk_is_set(rsc->flags, pe_rsc_unique) ? " (unique)" : "",
pcmk_is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)");
if (pcmk__list_of_multiple(bundle_data->replicas)) {
out->list_item(out, NULL, "Replica[%d]", replica->offset);
}
out->begin_list(out, NULL, NULL, NULL);
if (print_ip) {
out->message(out, crm_map_element_name(replica->ip->xml),
new_options, replica->ip, only_node, only_rsc);
}
if (print_child) {
out->message(out, crm_map_element_name(replica->child->xml),
new_options, replica->child, only_node, only_rsc);
}
if (print_ctnr) {
out->message(out, crm_map_element_name(replica->container->xml),
new_options, replica->container, only_node, only_rsc);
}
if (print_remote) {
out->message(out, crm_map_element_name(replica->remote->xml),
new_options, replica->remote, only_node, only_rsc);
}
out->end_list(out);
} else if (print_everything == FALSE && !(print_ip || print_child || print_ctnr || print_remote)) {
continue;
} else {
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Container bundle%s: %s [%s]%s%s",
(bundle_data->nreplicas > 1)? " set" : "",
rsc->id, bundle_data->image,
pcmk_is_set(rsc->flags, pe_rsc_unique) ? " (unique)" : "",
pcmk_is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)");
pe__bundle_replica_output_text(out, replica, pe__current_node(replica->container),
options);
}
}
PCMK__OUTPUT_LIST_FOOTER(out, rc);
return rc;
}
static void
print_bundle_replica(pe__bundle_replica_t *replica, const char *pre_text,
long options, void *print_data)
{
pe_node_t *node = NULL;
pe_resource_t *rsc = replica->child;
int offset = 0;
char buffer[LINE_MAX];
if(rsc == NULL) {
rsc = replica->container;
}
if (replica->remote) {
offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
rsc_printable_id(replica->remote));
} else {
offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
rsc_printable_id(replica->container));
}
if (replica->ipaddr) {
offset += snprintf(buffer + offset, LINE_MAX - offset, " (%s)",
replica->ipaddr);
}
node = pe__current_node(replica->container);
common_print(rsc, pre_text, buffer, node, options, print_data);
}
void
pe__print_bundle(pe_resource_t *rsc, const char *pre_text, long options,
void *print_data)
{
pe__bundle_variant_data_t *bundle_data = NULL;
char *child_text = NULL;
CRM_CHECK(rsc != NULL, return);
if (options & pe_print_xml) {
bundle_print_xml(rsc, pre_text, options, print_data);
return;
}
get_bundle_variant_data(bundle_data, rsc);
if (pre_text == NULL) {
pre_text = " ";
}
status_print("%sContainer bundle%s: %s [%s]%s%s\n",
pre_text, ((bundle_data->nreplicas > 1)? " set" : ""),
rsc->id, bundle_data->image,
pcmk_is_set(rsc->flags, pe_rsc_unique) ? " (unique)" : "",
pcmk_is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)");
if (options & pe_print_html) {
status_print("<br />\n<ul>\n");
}
for (GList *gIter = bundle_data->replicas; gIter != NULL;
gIter = gIter->next) {
pe__bundle_replica_t *replica = gIter->data;
CRM_ASSERT(replica);
if (options & pe_print_html) {
status_print("<li>");
}
if (pcmk_is_set(options, pe_print_implicit)) {
child_text = crm_strdup_printf(" %s", pre_text);
if (pcmk__list_of_multiple(bundle_data->replicas)) {
status_print(" %sReplica[%d]\n", pre_text, replica->offset);
}
if (options & pe_print_html) {
status_print("<br />\n<ul>\n");
}
print_rsc_in_list(replica->ip, child_text, options, print_data);
print_rsc_in_list(replica->container, child_text, options, print_data);
print_rsc_in_list(replica->remote, child_text, options, print_data);
print_rsc_in_list(replica->child, child_text, options, print_data);
if (options & pe_print_html) {
status_print("</ul>\n");
}
} else {
child_text = crm_strdup_printf("%s ", pre_text);
print_bundle_replica(replica, child_text, options, print_data);
}
free(child_text);
if (options & pe_print_html) {
status_print("</li>\n");
}
}
if (options & pe_print_html) {
status_print("</ul>\n");
}
}
static void
free_bundle_replica(pe__bundle_replica_t *replica)
{
if (replica == NULL) {
return;
}
if (replica->node) {
free(replica->node);
replica->node = NULL;
}
if (replica->ip) {
free_xml(replica->ip->xml);
replica->ip->xml = NULL;
replica->ip->fns->free(replica->ip);
replica->ip = NULL;
}
if (replica->container) {
free_xml(replica->container->xml);
replica->container->xml = NULL;
replica->container->fns->free(replica->container);
replica->container = NULL;
}
if (replica->remote) {
free_xml(replica->remote->xml);
replica->remote->xml = NULL;
replica->remote->fns->free(replica->remote);
replica->remote = NULL;
}
free(replica->ipaddr);
free(replica);
}
void
pe__free_bundle(pe_resource_t *rsc)
{
pe__bundle_variant_data_t *bundle_data = NULL;
CRM_CHECK(rsc != NULL, return);
get_bundle_variant_data(bundle_data, rsc);
pe_rsc_trace(rsc, "Freeing %s", rsc->id);
free(bundle_data->prefix);
free(bundle_data->image);
free(bundle_data->control_port);
free(bundle_data->host_network);
free(bundle_data->host_netmask);
free(bundle_data->ip_range_start);
free(bundle_data->container_network);
free(bundle_data->launcher_options);
free(bundle_data->container_command);
free(bundle_data->container_host_options);
g_list_free_full(bundle_data->replicas,
(GDestroyNotify) free_bundle_replica);
g_list_free_full(bundle_data->mounts, (GDestroyNotify)mount_free);
g_list_free_full(bundle_data->ports, (GDestroyNotify)port_free);
g_list_free(rsc->children);
if(bundle_data->child) {
free_xml(bundle_data->child->xml);
bundle_data->child->xml = NULL;
bundle_data->child->fns->free(bundle_data->child);
}
common_free(rsc);
}
enum rsc_role_e
pe__bundle_resource_state(const pe_resource_t *rsc, gboolean current)
{
enum rsc_role_e container_role = RSC_ROLE_UNKNOWN;
return container_role;
}
/*!
* \brief Get the number of configured replicas in a bundle
*
* \param[in] rsc Bundle resource
*
* \return Number of configured replicas, or 0 on error
*/
int
pe_bundle_replicas(const pe_resource_t *rsc)
{
if ((rsc == NULL) || (rsc->variant != pe_container)) {
return 0;
} else {
pe__bundle_variant_data_t *bundle_data = NULL;
get_bundle_variant_data(bundle_data, rsc);
return bundle_data->nreplicas;
}
}
void
pe__count_bundle(pe_resource_t *rsc)
{
pe__bundle_variant_data_t *bundle_data = NULL;
get_bundle_variant_data(bundle_data, rsc);
for (GList *item = bundle_data->replicas; item != NULL; item = item->next) {
pe__bundle_replica_t *replica = item->data;
if (replica->ip) {
replica->ip->fns->count(replica->ip);
}
if (replica->child) {
replica->child->fns->count(replica->child);
}
if (replica->container) {
replica->container->fns->count(replica->container);
}
if (replica->remote) {
replica->remote->fns->count(replica->remote);
}
}
}
gboolean
pe__bundle_is_filtered(pe_resource_t *rsc, GListPtr only_rsc, gboolean check_parent)
{
gboolean passes = FALSE;
pe__bundle_variant_data_t *bundle_data = NULL;
if (pcmk__str_in_list(only_rsc, rsc_printable_id(rsc))) {
passes = TRUE;
} else {
get_bundle_variant_data(bundle_data, rsc);
for (GList *gIter = bundle_data->replicas; gIter != NULL; gIter = gIter->next) {
pe__bundle_replica_t *replica = gIter->data;
if (replica->ip != NULL && !replica->ip->fns->is_filtered(replica->ip, only_rsc, FALSE)) {
passes = TRUE;
break;
} else if (replica->child != NULL && !replica->child->fns->is_filtered(replica->child, only_rsc, FALSE)) {
passes = TRUE;
break;
} else if (!replica->container->fns->is_filtered(replica->container, only_rsc, FALSE)) {
passes = TRUE;
break;
} else if (replica->remote != NULL && !replica->remote->fns->is_filtered(replica->remote, only_rsc, FALSE)) {
passes = TRUE;
break;
}
}
}
return !passes;
}
diff --git a/lib/pengine/clone.c b/lib/pengine/clone.c
index 0708fdc9ea..9b48d01d6f 100644
--- a/lib/pengine/clone.c
+++ b/lib/pengine/clone.c
@@ -1,1209 +1,1209 @@
/*
* Copyright 2004-2020 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/pengine/rules.h>
#include <crm/pengine/status.h>
#include <crm/pengine/internal.h>
#include <pe_status_private.h>
#include <crm/msg_xml.h>
#include <crm/common/xml_internal.h>
#define VARIANT_CLONE 1
#include "./variant.h"
void
pe__force_anon(const char *standard, pe_resource_t *rsc, const char *rid,
pe_working_set_t *data_set)
{
if (pe_rsc_is_clone(rsc)) {
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
pe_warn("Ignoring " XML_RSC_ATTR_UNIQUE " for %s because %s resources "
"such as %s can be used only as anonymous clones",
rsc->id, standard, rid);
clone_data->clone_node_max = 1;
clone_data->clone_max = QB_MIN(clone_data->clone_max,
g_list_length(data_set->nodes));
}
}
pe_resource_t *
find_clone_instance(pe_resource_t * rsc, const char *sub_id, pe_working_set_t * data_set)
{
char *child_id = NULL;
pe_resource_t *child = NULL;
const char *child_base = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
child_base = ID(clone_data->xml_obj_child);
child_id = crm_strdup_printf("%s:%s", child_base, sub_id);
child = pe_find_resource(rsc->children, child_id);
free(child_id);
return child;
}
pe_resource_t *
pe__create_clone_child(pe_resource_t *rsc, pe_working_set_t *data_set)
{
gboolean as_orphan = FALSE;
char *inc_num = NULL;
char *inc_max = NULL;
pe_resource_t *child_rsc = NULL;
xmlNode *child_copy = NULL;
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE);
if (clone_data->total_clones >= clone_data->clone_max) {
// If we've already used all available instances, this is an orphan
as_orphan = TRUE;
}
// Allocate instance numbers in numerical order (starting at 0)
inc_num = crm_itoa(clone_data->total_clones);
inc_max = crm_itoa(clone_data->clone_max);
child_copy = copy_xml(clone_data->xml_obj_child);
crm_xml_add(child_copy, XML_RSC_ATTR_INCARNATION, inc_num);
if (common_unpack(child_copy, &child_rsc, rsc, data_set) == FALSE) {
pe_err("Failed unpacking resource %s", crm_element_value(child_copy, XML_ATTR_ID));
child_rsc = NULL;
goto bail;
}
/* child_rsc->globally_unique = rsc->globally_unique; */
CRM_ASSERT(child_rsc);
clone_data->total_clones += 1;
pe_rsc_trace(child_rsc, "Setting clone attributes for: %s", child_rsc->id);
rsc->children = g_list_append(rsc->children, child_rsc);
if (as_orphan) {
pe__set_resource_flags_recursive(child_rsc, pe_rsc_orphan);
}
add_hash_param(child_rsc->meta, XML_RSC_ATTR_INCARNATION_MAX, inc_max);
pe_rsc_trace(rsc, "Added %s instance %s", rsc->id, child_rsc->id);
bail:
free(inc_num);
free(inc_max);
return child_rsc;
}
gboolean
clone_unpack(pe_resource_t * rsc, pe_working_set_t * data_set)
{
int lpc = 0;
xmlNode *a_child = NULL;
xmlNode *xml_obj = rsc->xml;
clone_variant_data_t *clone_data = NULL;
const char *ordered = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_ORDERED);
const char *max_clones = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_MAX);
const char *max_clones_node = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_NODEMAX);
pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
clone_data = calloc(1, sizeof(clone_variant_data_t));
rsc->variant_opaque = clone_data;
if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
const char *promoted_max = NULL;
const char *promoted_node_max = NULL;
promoted_max = g_hash_table_lookup(rsc->meta,
XML_RSC_ATTR_PROMOTED_MAX);
if (promoted_max == NULL) {
// @COMPAT deprecated since 2.0.0
promoted_max = g_hash_table_lookup(rsc->meta,
XML_RSC_ATTR_MASTER_MAX);
}
promoted_node_max = g_hash_table_lookup(rsc->meta,
XML_RSC_ATTR_PROMOTED_NODEMAX);
if (promoted_node_max == NULL) {
// @COMPAT deprecated since 2.0.0
promoted_node_max = g_hash_table_lookup(rsc->meta,
XML_RSC_ATTR_MASTER_NODEMAX);
}
clone_data->promoted_max = crm_parse_int(promoted_max, "1");
clone_data->promoted_node_max = crm_parse_int(promoted_node_max, "1");
}
// Implied by calloc()
/* clone_data->xml_obj_child = NULL; */
clone_data->clone_node_max = crm_parse_int(max_clones_node, "1");
if (max_clones) {
clone_data->clone_max = crm_parse_int(max_clones, "1");
} else if (pcmk__list_of_multiple(data_set->nodes)) {
clone_data->clone_max = g_list_length(data_set->nodes);
} else {
clone_data->clone_max = 1; /* Handy during crm_verify */
}
clone_data->ordered = crm_is_true(ordered);
if ((rsc->flags & pe_rsc_unique) == 0 && clone_data->clone_node_max > 1) {
pcmk__config_err("Ignoring " XML_RSC_ATTR_PROMOTED_MAX " for %s "
"because anonymous clones support only one instance "
"per node", rsc->id);
clone_data->clone_node_max = 1;
}
pe_rsc_trace(rsc, "Options for %s", rsc->id);
pe_rsc_trace(rsc, "\tClone max: %d", clone_data->clone_max);
pe_rsc_trace(rsc, "\tClone node max: %d", clone_data->clone_node_max);
pe_rsc_trace(rsc, "\tClone is unique: %s",
pe__rsc_bool_str(rsc, pe_rsc_unique));
pe_rsc_trace(rsc, "\tClone is promotable: %s",
pe__rsc_bool_str(rsc, pe_rsc_promotable));
// Clones may contain a single group or primitive
for (a_child = pcmk__xe_first_child(xml_obj); a_child != NULL;
a_child = pcmk__xe_next(a_child)) {
if (pcmk__str_any_of((const char *)a_child->name, XML_CIB_TAG_RESOURCE, XML_CIB_TAG_GROUP, NULL)) {
clone_data->xml_obj_child = a_child;
break;
}
}
if (clone_data->xml_obj_child == NULL) {
pcmk__config_err("%s has nothing to clone", rsc->id);
return FALSE;
}
/*
* Make clones ever so slightly sticky by default
*
* This helps ensure clone instances are not shuffled around the cluster
* for no benefit in situations when pre-allocation is not appropriate
*/
if (g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_STICKINESS) == NULL) {
add_hash_param(rsc->meta, XML_RSC_ATTR_STICKINESS, "1");
}
/* This ensures that the globally-unique value always exists for children to
* inherit when being unpacked, as well as in resource agents' environment.
*/
add_hash_param(rsc->meta, XML_RSC_ATTR_UNIQUE,
pe__rsc_bool_str(rsc, pe_rsc_unique));
if (clone_data->clone_max <= 0) {
/* Create one child instance so that unpack_find_resource() will hook up
* any orphans up to the parent correctly.
*/
if (pe__create_clone_child(rsc, data_set) == NULL) {
return FALSE;
}
} else {
// Create a child instance for each available instance number
for (lpc = 0; lpc < clone_data->clone_max; lpc++) {
if (pe__create_clone_child(rsc, data_set) == NULL) {
return FALSE;
}
}
}
pe_rsc_trace(rsc, "Added %d children to resource %s...", clone_data->clone_max, rsc->id);
return TRUE;
}
gboolean
clone_active(pe_resource_t * rsc, gboolean all)
{
GListPtr gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
gboolean child_active = child_rsc->fns->active(child_rsc, all);
if (all == FALSE && child_active) {
return TRUE;
} else if (all && child_active == FALSE) {
return FALSE;
}
}
if (all) {
return TRUE;
} else {
return FALSE;
}
}
static void
short_print(char *list, const char *prefix, const char *type, const char *suffix, long options, void *print_data)
{
if(suffix == NULL) {
suffix = "";
}
if (list) {
if (options & pe_print_html) {
status_print("<li>");
}
status_print("%s%s: [ %s ]%s", prefix, type, list, suffix);
if (options & pe_print_html) {
status_print("</li>\n");
} else if (options & pe_print_suppres_nl) {
/* nothing */
} else if ((options & pe_print_printf) || (options & pe_print_ncurses)) {
status_print("\n");
}
}
}
static const char *
configured_role_str(pe_resource_t * rsc)
{
const char *target_role = g_hash_table_lookup(rsc->meta,
XML_RSC_ATTR_TARGET_ROLE);
if ((target_role == NULL) && rsc->children && rsc->children->data) {
target_role = g_hash_table_lookup(((pe_resource_t*)rsc->children->data)->meta,
XML_RSC_ATTR_TARGET_ROLE);
}
return target_role;
}
static enum rsc_role_e
configured_role(pe_resource_t * rsc)
{
const char *target_role = configured_role_str(rsc);
if (target_role) {
return text2role(target_role);
}
return RSC_ROLE_UNKNOWN;
}
static void
clone_print_xml(pe_resource_t * rsc, const char *pre_text, long options, void *print_data)
{
char *child_text = crm_strdup_printf("%s ", pre_text);
const char *target_role = configured_role_str(rsc);
GListPtr gIter = rsc->children;
status_print("%s<clone ", pre_text);
status_print("id=\"%s\" ", rsc->id);
status_print("multi_state=\"%s\" ",
pe__rsc_bool_str(rsc, pe_rsc_promotable));
status_print("unique=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_unique));
status_print("managed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_managed));
status_print("failed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_failed));
status_print("failure_ignored=\"%s\" ",
pe__rsc_bool_str(rsc, pe_rsc_failure_ignored));
if (target_role) {
status_print("target_role=\"%s\" ", target_role);
}
status_print(">\n");
for (; gIter != NULL; gIter = gIter->next) {
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
child_rsc->fns->print(child_rsc, child_text, options, print_data);
}
status_print("%s</clone>\n", pre_text);
free(child_text);
}
bool is_set_recursive(pe_resource_t * rsc, long long flag, bool any)
{
GListPtr gIter;
bool all = !any;
if (pcmk_is_set(rsc->flags, flag)) {
if(any) {
return TRUE;
}
} else if(all) {
return FALSE;
}
for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
if(is_set_recursive(gIter->data, flag, any)) {
if(any) {
return TRUE;
}
} else if(all) {
return FALSE;
}
}
if(all) {
return TRUE;
}
return FALSE;
}
void
clone_print(pe_resource_t * rsc, const char *pre_text, long options, void *print_data)
{
char *list_text = NULL;
char *child_text = NULL;
char *stopped_list = NULL;
size_t list_text_len = 0;
size_t stopped_list_len = 0;
GListPtr master_list = NULL;
GListPtr started_list = NULL;
GListPtr gIter = rsc->children;
clone_variant_data_t *clone_data = NULL;
int active_instances = 0;
if (pre_text == NULL) {
pre_text = " ";
}
if (options & pe_print_xml) {
clone_print_xml(rsc, pre_text, options, print_data);
return;
}
get_clone_variant_data(clone_data, rsc);
child_text = crm_strdup_printf("%s ", pre_text);
status_print("%sClone Set: %s [%s]%s%s%s",
pre_text ? pre_text : "", rsc->id, ID(clone_data->xml_obj_child),
pcmk_is_set(rsc->flags, pe_rsc_promotable)? " (promotable)" : "",
pcmk_is_set(rsc->flags, pe_rsc_unique)? " (unique)" : "",
pcmk_is_set(rsc->flags, pe_rsc_managed)? "" : " (unmanaged)");
if (options & pe_print_html) {
status_print("\n<ul>\n");
} else if ((options & pe_print_log) == 0) {
status_print("\n");
}
for (; gIter != NULL; gIter = gIter->next) {
gboolean print_full = FALSE;
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
gboolean partially_active = child_rsc->fns->active(child_rsc, FALSE);
if (options & pe_print_clone_details) {
print_full = TRUE;
}
if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
// Print individual instance when unique (except stopped orphans)
if (partially_active || !pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
print_full = TRUE;
}
// Everything else in this block is for anonymous clones
} else if (pcmk_is_set(options, pe_print_pending)
&& (child_rsc->pending_task != NULL)
&& strcmp(child_rsc->pending_task, "probe")) {
// Print individual instance when non-probe action is pending
print_full = TRUE;
} else if (partially_active == FALSE) {
// List stopped instances when requested (except orphans)
if (!pcmk_is_set(child_rsc->flags, pe_rsc_orphan)
&& !pcmk_is_set(options, pe_print_clone_active)) {
pcmk__add_word(&stopped_list, &stopped_list_len, child_rsc->id);
}
} else if (is_set_recursive(child_rsc, pe_rsc_orphan, TRUE)
|| is_set_recursive(child_rsc, pe_rsc_managed, FALSE) == FALSE
|| is_set_recursive(child_rsc, pe_rsc_failed, TRUE)) {
// Print individual instance when active orphaned/unmanaged/failed
print_full = TRUE;
} else if (child_rsc->fns->active(child_rsc, TRUE)) {
// Instance of fully active anonymous clone
pe_node_t *location = child_rsc->fns->location(child_rsc, NULL, TRUE);
if (location) {
// Instance is active on a single node
enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
if (location->details->online == FALSE && location->details->unclean) {
print_full = TRUE;
} else if (a_role > RSC_ROLE_SLAVE) {
master_list = g_list_append(master_list, location);
} else {
started_list = g_list_append(started_list, location);
}
} else {
/* uncolocated group - bleh */
print_full = TRUE;
}
} else {
// Instance of partially active anonymous clone
print_full = TRUE;
}
if (print_full) {
if (options & pe_print_html) {
status_print("<li>\n");
}
child_rsc->fns->print(child_rsc, child_text, options, print_data);
if (options & pe_print_html) {
status_print("</li>\n");
}
}
}
/* Masters */
master_list = g_list_sort(master_list, sort_node_uname);
for (gIter = master_list; gIter; gIter = gIter->next) {
pe_node_t *host = gIter->data;
pcmk__add_word(&list_text, &list_text_len, host->details->uname);
active_instances++;
}
short_print(list_text, child_text, "Masters", NULL, options, print_data);
g_list_free(master_list);
free(list_text);
list_text = NULL;
list_text_len = 0;
/* Started/Slaves */
started_list = g_list_sort(started_list, sort_node_uname);
for (gIter = started_list; gIter; gIter = gIter->next) {
pe_node_t *host = gIter->data;
pcmk__add_word(&list_text, &list_text_len, host->details->uname);
active_instances++;
}
if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
enum rsc_role_e role = configured_role(rsc);
if(role == RSC_ROLE_SLAVE) {
short_print(list_text, child_text, "Slaves (target-role)", NULL, options, print_data);
} else {
short_print(list_text, child_text, "Slaves", NULL, options, print_data);
}
} else {
short_print(list_text, child_text, "Started", NULL, options, print_data);
}
g_list_free(started_list);
free(list_text);
list_text = NULL;
list_text_len = 0;
if (!pcmk_is_set(options, pe_print_clone_active)) {
const char *state = "Stopped";
enum rsc_role_e role = configured_role(rsc);
if (role == RSC_ROLE_STOPPED) {
state = "Stopped (disabled)";
}
if (!pcmk_is_set(rsc->flags, pe_rsc_unique)
&& (clone_data->clone_max > active_instances)) {
GListPtr nIter;
GListPtr list = g_hash_table_get_values(rsc->allowed_nodes);
/* Custom stopped list for non-unique clones */
free(stopped_list);
stopped_list = NULL;
stopped_list_len = 0;
if (list == NULL) {
/* Clusters with symmetrical=false haven't calculated allowed_nodes yet
* If we've not probed for them yet, the Stopped list will be empty
*/
list = g_hash_table_get_values(rsc->known_on);
}
list = g_list_sort(list, sort_node_uname);
for (nIter = list; nIter != NULL; nIter = nIter->next) {
pe_node_t *node = (pe_node_t *)nIter->data;
if (pe_find_node(rsc->running_on, node->details->uname) == NULL) {
pcmk__add_word(&stopped_list, &stopped_list_len,
node->details->uname);
}
}
g_list_free(list);
}
short_print(stopped_list, child_text, state, NULL, options, print_data);
free(stopped_list);
}
if (options & pe_print_html) {
status_print("</ul>\n");
}
free(child_text);
}
-PCMK__OUTPUT_ARGS("clone", "unsigned int", "pe_resource_t *", "GListPtr", "GListPtr")
+PCMK__OUTPUT_ARGS("clone", "unsigned int", "pe_resource_t *", "GList *", "GList *")
int
pe__clone_xml(pcmk__output_t *out, va_list args)
{
unsigned int options = va_arg(args, unsigned int);
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
- GListPtr only_node = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
- GListPtr gIter = rsc->children;
+ GList *gIter = rsc->children;
int rc = pcmk_rc_no_output;
gboolean printed_header = FALSE;
gboolean print_everything = TRUE;
if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
return rc;
}
print_everything = pcmk__str_in_list(only_rsc, rsc_printable_id(rsc)) ||
(strstr(rsc->id, ":") != NULL && pcmk__str_in_list(only_rsc, rsc->id));
for (; gIter != NULL; gIter = gIter->next) {
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
continue;
}
if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
continue;
}
if (!printed_header) {
printed_header = TRUE;
rc = pe__name_and_nvpairs_xml(out, true, "clone", 8,
"id", rsc->id,
"multi_state", pe__rsc_bool_str(rsc, pe_rsc_promotable),
"unique", pe__rsc_bool_str(rsc, pe_rsc_unique),
"managed", pe__rsc_bool_str(rsc, pe_rsc_managed),
"disabled", pcmk__btoa(pe__resource_is_disabled(rsc)),
"failed", pe__rsc_bool_str(rsc, pe_rsc_failed),
"failure_ignored", pe__rsc_bool_str(rsc, pe_rsc_failure_ignored),
"target_role", configured_role_str(rsc));
CRM_ASSERT(rc == pcmk_rc_ok);
}
out->message(out, crm_map_element_name(child_rsc->xml), options,
child_rsc, only_node, only_rsc);
}
if (printed_header) {
pcmk__output_xml_pop_parent(out);
}
return rc;
}
-PCMK__OUTPUT_ARGS("clone", "unsigned int", "pe_resource_t *", "GListPtr", "GListPtr")
+PCMK__OUTPUT_ARGS("clone", "unsigned int", "pe_resource_t *", "GList *", "GList *")
int
pe__clone_html(pcmk__output_t *out, va_list args)
{
unsigned int options = va_arg(args, unsigned int);
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
- GListPtr only_node = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
char *list_text = NULL;
char *stopped_list = NULL;
size_t list_text_len = 0;
size_t stopped_list_len = 0;
- GListPtr master_list = NULL;
- GListPtr started_list = NULL;
- GListPtr gIter = rsc->children;
+ GList *master_list = NULL;
+ GList *started_list = NULL;
+ GList *gIter = rsc->children;
clone_variant_data_t *clone_data = NULL;
int active_instances = 0;
int rc = pcmk_rc_no_output;
gboolean print_everything = TRUE;
get_clone_variant_data(clone_data, rsc);
if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
return rc;
}
print_everything = pcmk__str_in_list(only_rsc, rsc_printable_id(rsc)) ||
(strstr(rsc->id, ":") != NULL && pcmk__str_in_list(only_rsc, rsc->id));
out->begin_list(out, NULL, NULL, "Clone Set: %s [%s]%s%s%s%s",
rsc->id, ID(clone_data->xml_obj_child),
pcmk_is_set(rsc->flags, pe_rsc_promotable) ? " (promotable)" : "",
pcmk_is_set(rsc->flags, pe_rsc_unique) ? " (unique)" : "",
pcmk_is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)",
pe__resource_is_disabled(rsc) ? " (disabled)" : "");
rc = pcmk_rc_ok;
for (; gIter != NULL; gIter = gIter->next) {
gboolean print_full = FALSE;
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
gboolean partially_active = child_rsc->fns->active(child_rsc, FALSE);
if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
continue;
}
if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
continue;
}
if (options & pe_print_clone_details) {
print_full = TRUE;
}
if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
// Print individual instance when unique (except stopped orphans)
if (partially_active || !pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
print_full = TRUE;
}
// Everything else in this block is for anonymous clones
} else if (pcmk_is_set(options, pe_print_pending)
&& (child_rsc->pending_task != NULL)
&& strcmp(child_rsc->pending_task, "probe")) {
// Print individual instance when non-probe action is pending
print_full = TRUE;
} else if (partially_active == FALSE) {
// List stopped instances when requested (except orphans)
if (!pcmk_is_set(child_rsc->flags, pe_rsc_orphan)
&& !pcmk_is_set(options, pe_print_clone_active)) {
pcmk__add_word(&stopped_list, &stopped_list_len, child_rsc->id);
}
} else if (is_set_recursive(child_rsc, pe_rsc_orphan, TRUE)
|| is_set_recursive(child_rsc, pe_rsc_managed, FALSE) == FALSE
|| is_set_recursive(child_rsc, pe_rsc_failed, TRUE)) {
// Print individual instance when active orphaned/unmanaged/failed
print_full = TRUE;
} else if (child_rsc->fns->active(child_rsc, TRUE)) {
// Instance of fully active anonymous clone
pe_node_t *location = child_rsc->fns->location(child_rsc, NULL, TRUE);
if (location) {
// Instance is active on a single node
enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
if (location->details->online == FALSE && location->details->unclean) {
print_full = TRUE;
} else if (a_role > RSC_ROLE_SLAVE) {
master_list = g_list_append(master_list, location);
} else {
started_list = g_list_append(started_list, location);
}
} else {
/* uncolocated group - bleh */
print_full = TRUE;
}
} else {
// Instance of partially active anonymous clone
print_full = TRUE;
}
if (print_full) {
- GListPtr all = NULL;
+ GList *all = NULL;
/* Print every resource that's a child of this clone. */
all = g_list_prepend(all, strdup("*"));
out->message(out, crm_map_element_name(child_rsc->xml), options,
child_rsc, only_node, all);
g_list_free_full(all, free);
}
}
if (pcmk_is_set(options, pe_print_clone_details)) {
free(stopped_list);
out->end_list(out);
return pcmk_rc_ok;
}
/* Masters */
master_list = g_list_sort(master_list, sort_node_uname);
for (gIter = master_list; gIter; gIter = gIter->next) {
pe_node_t *host = gIter->data;
if (!pcmk__str_in_list(only_node, host->details->uname)) {
continue;
}
pcmk__add_word(&list_text, &list_text_len, host->details->uname);
active_instances++;
}
if (list_text != NULL) {
out->list_item(out, NULL, " Masters: [ %s ]", list_text);
g_list_free(master_list);
free(list_text);
list_text = NULL;
list_text_len = 0;
}
/* Started/Slaves */
started_list = g_list_sort(started_list, sort_node_uname);
for (gIter = started_list; gIter; gIter = gIter->next) {
pe_node_t *host = gIter->data;
if (!pcmk__str_in_list(only_node, host->details->uname)) {
continue;
}
pcmk__add_word(&list_text, &list_text_len, host->details->uname);
active_instances++;
}
if (list_text != NULL) {
if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
enum rsc_role_e role = configured_role(rsc);
if(role == RSC_ROLE_SLAVE) {
out->list_item(out, NULL, " Slaves (target-role): [ %s ]", list_text);
} else {
out->list_item(out, NULL, " Slaves: [ %s ]", list_text);
}
} else {
out->list_item(out, NULL, " Started: [ %s ]", list_text);
}
g_list_free(started_list);
free(list_text);
list_text = NULL;
list_text_len = 0;
}
if (!pcmk_is_set(options, pe_print_clone_active)) {
const char *state = "Stopped";
enum rsc_role_e role = configured_role(rsc);
if (role == RSC_ROLE_STOPPED) {
state = "Stopped (disabled)";
}
if (!pcmk_is_set(rsc->flags, pe_rsc_unique)
&& (clone_data->clone_max > active_instances)) {
- GListPtr nIter;
- GListPtr list = g_hash_table_get_values(rsc->allowed_nodes);
+ GList *nIter;
+ GList *list = g_hash_table_get_values(rsc->allowed_nodes);
/* Custom stopped list for non-unique clones */
free(stopped_list);
stopped_list = NULL;
stopped_list_len = 0;
if (list == NULL) {
/* Clusters with symmetrical=false haven't calculated allowed_nodes yet
* If we've not probed for them yet, the Stopped list will be empty
*/
list = g_hash_table_get_values(rsc->known_on);
}
list = g_list_sort(list, sort_node_uname);
for (nIter = list; nIter != NULL; nIter = nIter->next) {
pe_node_t *node = (pe_node_t *)nIter->data;
if (pe_find_node(rsc->running_on, node->details->uname) == NULL &&
pcmk__str_in_list(only_node, node->details->uname)) {
pcmk__add_word(&stopped_list, &stopped_list_len,
node->details->uname);
}
}
g_list_free(list);
}
if (stopped_list != NULL) {
out->list_item(out, NULL, " %s: [ %s ]", state, stopped_list);
free(stopped_list);
stopped_list_len = 0;
}
}
out->end_list(out);
return rc;
}
-PCMK__OUTPUT_ARGS("clone", "unsigned int", "pe_resource_t *", "GListPtr", "GListPtr")
+PCMK__OUTPUT_ARGS("clone", "unsigned int", "pe_resource_t *", "GList *", "GList *")
int
pe__clone_text(pcmk__output_t *out, va_list args)
{
unsigned int options = va_arg(args, unsigned int);
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
- GListPtr only_node = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
char *list_text = NULL;
char *stopped_list = NULL;
size_t list_text_len = 0;
size_t stopped_list_len = 0;
- GListPtr master_list = NULL;
- GListPtr started_list = NULL;
- GListPtr gIter = rsc->children;
+ GList *master_list = NULL;
+ GList *started_list = NULL;
+ GList *gIter = rsc->children;
clone_variant_data_t *clone_data = NULL;
int active_instances = 0;
int rc = pcmk_rc_no_output;
gboolean print_everything = TRUE;
get_clone_variant_data(clone_data, rsc);
if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
return rc;
}
print_everything = pcmk__str_in_list(only_rsc, rsc_printable_id(rsc)) ||
(strstr(rsc->id, ":") != NULL && pcmk__str_in_list(only_rsc, rsc->id));
out->begin_list(out, NULL, NULL, "Clone Set: %s [%s]%s%s%s%s",
rsc->id, ID(clone_data->xml_obj_child),
pcmk_is_set(rsc->flags, pe_rsc_promotable) ? " (promotable)" : "",
pcmk_is_set(rsc->flags, pe_rsc_unique) ? " (unique)" : "",
pcmk_is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)",
pe__resource_is_disabled(rsc) ? " (disabled)" : "");
rc = pcmk_rc_ok;
for (; gIter != NULL; gIter = gIter->next) {
gboolean print_full = FALSE;
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
gboolean partially_active = child_rsc->fns->active(child_rsc, FALSE);
if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
continue;
}
if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
continue;
}
if (options & pe_print_clone_details) {
print_full = TRUE;
}
if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
// Print individual instance when unique (except stopped orphans)
if (partially_active || !pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
print_full = TRUE;
}
// Everything else in this block is for anonymous clones
} else if (pcmk_is_set(options, pe_print_pending)
&& (child_rsc->pending_task != NULL)
&& strcmp(child_rsc->pending_task, "probe")) {
// Print individual instance when non-probe action is pending
print_full = TRUE;
} else if (partially_active == FALSE) {
// List stopped instances when requested (except orphans)
if (!pcmk_is_set(child_rsc->flags, pe_rsc_orphan)
&& !pcmk_is_set(options, pe_print_clone_active)) {
pcmk__add_word(&stopped_list, &stopped_list_len, child_rsc->id);
}
} else if (is_set_recursive(child_rsc, pe_rsc_orphan, TRUE)
|| is_set_recursive(child_rsc, pe_rsc_managed, FALSE) == FALSE
|| is_set_recursive(child_rsc, pe_rsc_failed, TRUE)) {
// Print individual instance when active orphaned/unmanaged/failed
print_full = TRUE;
} else if (child_rsc->fns->active(child_rsc, TRUE)) {
// Instance of fully active anonymous clone
pe_node_t *location = child_rsc->fns->location(child_rsc, NULL, TRUE);
if (location) {
// Instance is active on a single node
enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
if (location->details->online == FALSE && location->details->unclean) {
print_full = TRUE;
} else if (a_role > RSC_ROLE_SLAVE) {
master_list = g_list_append(master_list, location);
} else {
started_list = g_list_append(started_list, location);
}
} else {
/* uncolocated group - bleh */
print_full = TRUE;
}
} else {
// Instance of partially active anonymous clone
print_full = TRUE;
}
if (print_full) {
- GListPtr all = NULL;
+ GList *all = NULL;
/* Print every resource that's a child of this clone. */
all = g_list_prepend(all, strdup("*"));
out->message(out, crm_map_element_name(child_rsc->xml), options,
child_rsc, only_node, all);
g_list_free_full(all, free);
}
}
if (pcmk_is_set(options, pe_print_clone_details)) {
free(stopped_list);
out->end_list(out);
return pcmk_rc_ok;
}
/* Masters */
master_list = g_list_sort(master_list, sort_node_uname);
for (gIter = master_list; gIter; gIter = gIter->next) {
pe_node_t *host = gIter->data;
if (!pcmk__str_in_list(only_node, host->details->uname)) {
continue;
}
pcmk__add_word(&list_text, &list_text_len, host->details->uname);
active_instances++;
}
if (list_text != NULL) {
out->list_item(out, "Masters", "[ %s ]", list_text);
g_list_free(master_list);
free(list_text);
list_text = NULL;
list_text_len = 0;
}
/* Started/Slaves */
started_list = g_list_sort(started_list, sort_node_uname);
for (gIter = started_list; gIter; gIter = gIter->next) {
pe_node_t *host = gIter->data;
if (!pcmk__str_in_list(only_node, host->details->uname)) {
continue;
}
pcmk__add_word(&list_text, &list_text_len, host->details->uname);
active_instances++;
}
if (list_text != NULL) {
if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
enum rsc_role_e role = configured_role(rsc);
if(role == RSC_ROLE_SLAVE) {
out->list_item(out, "Slaves (target-role)", "[ %s ]", list_text);
} else {
out->list_item(out, "Slaves", "[ %s ]", list_text);
}
} else {
out->list_item(out, "Started", "[ %s ]", list_text);
}
g_list_free(started_list);
free(list_text);
list_text = NULL;
}
if (!pcmk_is_set(options, pe_print_clone_active)) {
const char *state = "Stopped";
enum rsc_role_e role = configured_role(rsc);
if (role == RSC_ROLE_STOPPED) {
state = "Stopped (disabled)";
}
if (!pcmk_is_set(rsc->flags, pe_rsc_unique)
&& (clone_data->clone_max > active_instances)) {
- GListPtr nIter;
- GListPtr list = g_hash_table_get_values(rsc->allowed_nodes);
+ GList *nIter;
+ GList *list = g_hash_table_get_values(rsc->allowed_nodes);
/* Custom stopped list for non-unique clones */
free(stopped_list);
stopped_list = NULL;
stopped_list_len = 0;
if (list == NULL) {
/* Clusters with symmetrical=false haven't calculated allowed_nodes yet
* If we've not probed for them yet, the Stopped list will be empty
*/
list = g_hash_table_get_values(rsc->known_on);
}
list = g_list_sort(list, sort_node_uname);
for (nIter = list; nIter != NULL; nIter = nIter->next) {
pe_node_t *node = (pe_node_t *)nIter->data;
if (pe_find_node(rsc->running_on, node->details->uname) == NULL &&
pcmk__str_in_list(only_node, node->details->uname)) {
pcmk__add_word(&stopped_list, &stopped_list_len,
node->details->uname);
}
}
g_list_free(list);
}
if (stopped_list != NULL) {
out->list_item(out, state, "[ %s ]", stopped_list);
free(stopped_list);
}
}
out->end_list(out);
return rc;
}
void
clone_free(pe_resource_t * rsc)
{
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
pe_rsc_trace(rsc, "Freeing %s", rsc->id);
for (GListPtr gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
CRM_ASSERT(child_rsc);
pe_rsc_trace(child_rsc, "Freeing child %s", child_rsc->id);
free_xml(child_rsc->xml);
child_rsc->xml = NULL;
/* There could be a saved unexpanded xml */
free_xml(child_rsc->orig_xml);
child_rsc->orig_xml = NULL;
child_rsc->fns->free(child_rsc);
}
g_list_free(rsc->children);
if (clone_data) {
CRM_ASSERT(clone_data->demote_notify == NULL);
CRM_ASSERT(clone_data->stop_notify == NULL);
CRM_ASSERT(clone_data->start_notify == NULL);
CRM_ASSERT(clone_data->promote_notify == NULL);
}
common_free(rsc);
}
enum rsc_role_e
clone_resource_state(const pe_resource_t * rsc, gboolean current)
{
enum rsc_role_e clone_role = RSC_ROLE_UNKNOWN;
GListPtr gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, current);
if (a_role > clone_role) {
clone_role = a_role;
}
}
pe_rsc_trace(rsc, "%s role: %s", rsc->id, role2text(clone_role));
return clone_role;
}
/*!
* \internal
* \brief Check whether a clone has an instance for every node
*
* \param[in] rsc Clone to check
* \param[in] data_set Cluster state
*/
bool
pe__is_universal_clone(pe_resource_t *rsc,
pe_working_set_t *data_set)
{
if (pe_rsc_is_clone(rsc)) {
clone_variant_data_t *clone_data = NULL;
get_clone_variant_data(clone_data, rsc);
if (clone_data->clone_max == g_list_length(data_set->nodes)) {
return TRUE;
}
}
return FALSE;
}
gboolean
pe__clone_is_filtered(pe_resource_t *rsc, GListPtr only_rsc, gboolean check_parent)
{
gboolean passes = FALSE;
clone_variant_data_t *clone_data = NULL;
if (pcmk__str_in_list(only_rsc, rsc_printable_id(rsc))) {
passes = TRUE;
} else {
get_clone_variant_data(clone_data, rsc);
passes = pcmk__str_in_list(only_rsc, ID(clone_data->xml_obj_child));
if (!passes) {
for (GListPtr gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
if (!child_rsc->fns->is_filtered(child_rsc, only_rsc, FALSE)) {
passes = TRUE;
break;
}
}
}
}
return !passes;
}
diff --git a/lib/pengine/group.c b/lib/pengine/group.c
index 33aa177dfb..58c9f7c9bc 100644
--- a/lib/pengine/group.c
+++ b/lib/pengine/group.c
@@ -1,407 +1,407 @@
/*
* Copyright 2004-2020 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/pengine/rules.h>
#include <crm/pengine/status.h>
#include <crm/pengine/internal.h>
#include <crm/msg_xml.h>
#include <crm/common/xml_internal.h>
#include <pe_status_private.h>
#define VARIANT_GROUP 1
#include "./variant.h"
gboolean
group_unpack(pe_resource_t * rsc, pe_working_set_t * data_set)
{
xmlNode *xml_obj = rsc->xml;
xmlNode *xml_native_rsc = NULL;
group_variant_data_t *group_data = NULL;
const char *group_ordered = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_ORDERED);
const char *group_colocated = g_hash_table_lookup(rsc->meta, "collocated");
const char *clone_id = NULL;
pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
group_data = calloc(1, sizeof(group_variant_data_t));
group_data->num_children = 0;
group_data->first_child = NULL;
group_data->last_child = NULL;
rsc->variant_opaque = group_data;
// We don't actually need the null checks but it speeds up the common case
if ((group_ordered == NULL)
|| (crm_str_to_boolean(group_ordered, &(group_data->ordered)) < 0)) {
group_data->ordered = TRUE;
}
if ((group_colocated == NULL)
|| (crm_str_to_boolean(group_colocated, &(group_data->colocated)) < 0)) {
group_data->colocated = TRUE;
}
clone_id = crm_element_value(rsc->xml, XML_RSC_ATTR_INCARNATION);
for (xml_native_rsc = pcmk__xe_first_child(xml_obj); xml_native_rsc != NULL;
xml_native_rsc = pcmk__xe_next(xml_native_rsc)) {
if (pcmk__str_eq((const char *)xml_native_rsc->name,
XML_CIB_TAG_RESOURCE, pcmk__str_none)) {
pe_resource_t *new_rsc = NULL;
crm_xml_add(xml_native_rsc, XML_RSC_ATTR_INCARNATION, clone_id);
if (common_unpack(xml_native_rsc, &new_rsc, rsc, data_set) == FALSE) {
pe_err("Failed unpacking resource %s", crm_element_value(xml_obj, XML_ATTR_ID));
if (new_rsc != NULL && new_rsc->fns != NULL) {
new_rsc->fns->free(new_rsc);
}
continue;
}
group_data->num_children++;
rsc->children = g_list_append(rsc->children, new_rsc);
if (group_data->first_child == NULL) {
group_data->first_child = new_rsc;
}
group_data->last_child = new_rsc;
pe_rsc_trace(rsc, "Added %s member %s", rsc->id, new_rsc->id);
}
}
if (group_data->num_children == 0) {
pcmk__config_warn("Group %s does not have any children", rsc->id);
return TRUE; // Allow empty groups, children can be added later
}
pe_rsc_trace(rsc, "Added %d children to resource %s...", group_data->num_children, rsc->id);
return TRUE;
}
gboolean
group_active(pe_resource_t * rsc, gboolean all)
{
gboolean c_all = TRUE;
gboolean c_any = FALSE;
GListPtr gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
if (child_rsc->fns->active(child_rsc, all)) {
c_any = TRUE;
} else {
c_all = FALSE;
}
}
if (c_any == FALSE) {
return FALSE;
} else if (all && c_all == FALSE) {
return FALSE;
}
return TRUE;
}
static void
group_print_xml(pe_resource_t * rsc, const char *pre_text, long options, void *print_data)
{
GListPtr gIter = rsc->children;
char *child_text = crm_strdup_printf("%s ", pre_text);
status_print("%s<group id=\"%s\" ", pre_text, rsc->id);
status_print("number_resources=\"%d\" ", g_list_length(rsc->children));
status_print(">\n");
for (; gIter != NULL; gIter = gIter->next) {
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
child_rsc->fns->print(child_rsc, child_text, options, print_data);
}
status_print("%s</group>\n", pre_text);
free(child_text);
}
void
group_print(pe_resource_t * rsc, const char *pre_text, long options, void *print_data)
{
char *child_text = NULL;
GListPtr gIter = rsc->children;
if (pre_text == NULL) {
pre_text = " ";
}
if (options & pe_print_xml) {
group_print_xml(rsc, pre_text, options, print_data);
return;
}
child_text = crm_strdup_printf("%s ", pre_text);
status_print("%sResource Group: %s", pre_text ? pre_text : "", rsc->id);
if (options & pe_print_html) {
status_print("\n<ul>\n");
} else if ((options & pe_print_log) == 0) {
status_print("\n");
}
if (options & pe_print_brief) {
print_rscs_brief(rsc->children, child_text, options, print_data, TRUE);
} else {
for (; gIter != NULL; gIter = gIter->next) {
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
if (options & pe_print_html) {
status_print("<li>\n");
}
child_rsc->fns->print(child_rsc, child_text, options, print_data);
if (options & pe_print_html) {
status_print("</li>\n");
}
}
}
if (options & pe_print_html) {
status_print("</ul>\n");
}
free(child_text);
}
-PCMK__OUTPUT_ARGS("group", "unsigned int", "pe_resource_t *", "GListPtr", "GListPtr")
+PCMK__OUTPUT_ARGS("group", "unsigned int", "pe_resource_t *", "GList *", "GList *")
int
pe__group_xml(pcmk__output_t *out, va_list args)
{
unsigned int options = va_arg(args, unsigned int);
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
- GListPtr only_node = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
- GListPtr gIter = rsc->children;
+ GList *gIter = rsc->children;
char *count = crm_itoa(g_list_length(gIter));
int rc = pcmk_rc_no_output;
gboolean print_everything = TRUE;
if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
free(count);
return rc;
}
print_everything = pcmk__str_in_list(only_rsc, rsc_printable_id(rsc)) ||
(strstr(rsc->id, ":") != NULL && pcmk__str_in_list(only_rsc, rsc->id));
for (; gIter != NULL; gIter = gIter->next) {
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
continue;
}
if (rc == pcmk_rc_no_output) {
rc = pe__name_and_nvpairs_xml(out, true, "group", 4
, "id", rsc->id
, "number_resources", count
, "managed", pe__rsc_bool_str(rsc, pe_rsc_managed)
, "disabled", pcmk__btoa(pe__resource_is_disabled(rsc)));
free(count);
CRM_ASSERT(rc == pcmk_rc_ok);
}
out->message(out, crm_map_element_name(child_rsc->xml), options, child_rsc,
only_node, only_rsc);
}
if (rc == pcmk_rc_ok) {
pcmk__output_xml_pop_parent(out);
}
return rc;
}
-PCMK__OUTPUT_ARGS("group", "unsigned int", "pe_resource_t *", "GListPtr", "GListPtr")
+PCMK__OUTPUT_ARGS("group", "unsigned int", "pe_resource_t *", "GList *", "GList *")
int
pe__group_html(pcmk__output_t *out, va_list args)
{
unsigned int options = va_arg(args, unsigned int);
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
- GListPtr only_node = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
int rc = pcmk_rc_no_output;
gboolean print_everything = TRUE;
if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
return rc;
}
print_everything = pcmk__str_in_list(only_rsc, rsc_printable_id(rsc)) ||
(strstr(rsc->id, ":") != NULL && pcmk__str_in_list(only_rsc, rsc->id));
if (options & pe_print_brief) {
- GListPtr rscs = pe__filter_rsc_list(rsc->children, only_rsc);
+ GList *rscs = pe__filter_rsc_list(rsc->children, only_rsc);
if (rscs != NULL) {
out->begin_list(out, NULL, NULL, "Resource Group: %s%s%s", rsc->id,
pcmk_is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)",
pe__resource_is_disabled(rsc) ? " (disabled)" : "");
pe__rscs_brief_output(out, rscs, options, TRUE);
rc = pcmk_rc_ok;
g_list_free(rscs);
}
} else {
- for (GListPtr gIter = rsc->children; gIter; gIter = gIter->next) {
+ for (GList *gIter = rsc->children; gIter; gIter = gIter->next) {
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
continue;
}
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Resource Group: %s%s%s", rsc->id,
pcmk_is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)",
pe__resource_is_disabled(rsc) ? " (disabled)" : "");
out->message(out, crm_map_element_name(child_rsc->xml), options,
child_rsc, only_node, only_rsc);
}
}
PCMK__OUTPUT_LIST_FOOTER(out, rc);
return rc;
}
-PCMK__OUTPUT_ARGS("group", "unsigned int", "pe_resource_t *", "GListPtr", "GListPtr")
+PCMK__OUTPUT_ARGS("group", "unsigned int", "pe_resource_t *", "GList *", "GList *")
int
pe__group_text(pcmk__output_t *out, va_list args)
{
unsigned int options = va_arg(args, unsigned int);
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
- GListPtr only_node = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
int rc = pcmk_rc_no_output;
gboolean print_everything = TRUE;
if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
return rc;
}
print_everything = pcmk__str_in_list(only_rsc, rsc_printable_id(rsc)) ||
(strstr(rsc->id, ":") != NULL && pcmk__str_in_list(only_rsc, rsc->id));
if (options & pe_print_brief) {
- GListPtr rscs = pe__filter_rsc_list(rsc->children, only_rsc);
+ GList *rscs = pe__filter_rsc_list(rsc->children, only_rsc);
if (rscs != NULL) {
out->begin_list(out, NULL, NULL, "Resource Group: %s%s%s", rsc->id,
pcmk_is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)",
pe__resource_is_disabled(rsc) ? " (disabled)" : "");
pe__rscs_brief_output(out, rscs, options, TRUE);
rc = pcmk_rc_ok;
g_list_free(rscs);
}
} else {
- for (GListPtr gIter = rsc->children; gIter; gIter = gIter->next) {
+ for (GList *gIter = rsc->children; gIter; gIter = gIter->next) {
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
continue;
}
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Resource Group: %s%s%s", rsc->id,
pcmk_is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)",
pe__resource_is_disabled(rsc) ? " (disabled)" : "");
out->message(out, crm_map_element_name(child_rsc->xml), options,
child_rsc, only_node, only_rsc);
}
}
PCMK__OUTPUT_LIST_FOOTER(out, rc);
return rc;
}
void
group_free(pe_resource_t * rsc)
{
CRM_CHECK(rsc != NULL, return);
pe_rsc_trace(rsc, "Freeing %s", rsc->id);
for (GListPtr gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
CRM_ASSERT(child_rsc);
pe_rsc_trace(child_rsc, "Freeing child %s", child_rsc->id);
child_rsc->fns->free(child_rsc);
}
pe_rsc_trace(rsc, "Freeing child list");
g_list_free(rsc->children);
common_free(rsc);
}
enum rsc_role_e
group_resource_state(const pe_resource_t * rsc, gboolean current)
{
enum rsc_role_e group_role = RSC_ROLE_UNKNOWN;
GListPtr gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
enum rsc_role_e role = child_rsc->fns->state(child_rsc, current);
if (role > group_role) {
group_role = role;
}
}
pe_rsc_trace(rsc, "%s role: %s", rsc->id, role2text(group_role));
return group_role;
}
gboolean
pe__group_is_filtered(pe_resource_t *rsc, GListPtr only_rsc, gboolean check_parent)
{
gboolean passes = FALSE;
if (check_parent && pcmk__str_in_list(only_rsc, rsc_printable_id(uber_parent(rsc)))) {
passes = TRUE;
} else if (pcmk__str_in_list(only_rsc, rsc_printable_id(rsc))) {
passes = TRUE;
} else if (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(only_rsc, rsc->id)) {
passes = TRUE;
} else {
for (GListPtr gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
if (!child_rsc->fns->is_filtered(child_rsc, only_rsc, FALSE)) {
passes = TRUE;
break;
}
}
}
return !passes;
}
diff --git a/lib/pengine/native.c b/lib/pengine/native.c
index 38e935053e..6f27d7b269 100644
--- a/lib/pengine/native.c
+++ b/lib/pengine/native.c
@@ -1,1376 +1,1376 @@
/*
* Copyright 2004-2020 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/pengine/rules.h>
#include <crm/pengine/status.h>
#include <crm/pengine/complex.h>
#include <crm/pengine/internal.h>
#include <crm/msg_xml.h>
#include <pe_status_private.h>
#define VARIANT_NATIVE 1
#include "./variant.h"
/*!
* \internal
* \brief Check whether a resource is active on multiple nodes
*/
static bool
is_multiply_active(pe_resource_t *rsc)
{
unsigned int count = 0;
if (rsc->variant == pe_native) {
pe__find_active_requires(rsc, &count);
}
return count > 1;
}
static void
native_priority_to_node(pe_resource_t * rsc, pe_node_t * node)
{
int priority = 0;
if (rsc->priority == 0) {
return;
}
if (rsc->role == RSC_ROLE_MASTER) {
// Promoted instance takes base priority + 1
priority = rsc->priority + 1;
} else {
priority = rsc->priority;
}
node->details->priority += priority;
pe_rsc_trace(rsc, "Node '%s' now has priority %d with %s'%s' (priority: %d%s)",
node->details->uname, node->details->priority,
rsc->role == RSC_ROLE_MASTER ? "promoted " : "",
rsc->id, rsc->priority,
rsc->role == RSC_ROLE_MASTER ? " + 1" : "");
/* Priority of a resource running on a guest node is added to the cluster
* node as well. */
if (node->details->remote_rsc
&& node->details->remote_rsc->container) {
GListPtr gIter = node->details->remote_rsc->container->running_on;
for (; gIter != NULL; gIter = gIter->next) {
pe_node_t *a_node = gIter->data;
a_node->details->priority += priority;
pe_rsc_trace(rsc, "Node '%s' now has priority %d with %s'%s' (priority: %d%s) "
"from guest node '%s'",
a_node->details->uname, a_node->details->priority,
rsc->role == RSC_ROLE_MASTER ? "promoted " : "",
rsc->id, rsc->priority,
rsc->role == RSC_ROLE_MASTER ? " + 1" : "",
node->details->uname);
}
}
}
void
native_add_running(pe_resource_t * rsc, pe_node_t * node, pe_working_set_t * data_set)
{
GListPtr gIter = rsc->running_on;
CRM_CHECK(node != NULL, return);
for (; gIter != NULL; gIter = gIter->next) {
pe_node_t *a_node = (pe_node_t *) gIter->data;
CRM_CHECK(a_node != NULL, return);
if (pcmk__str_eq(a_node->details->id, node->details->id, pcmk__str_casei)) {
return;
}
}
pe_rsc_trace(rsc, "Adding %s to %s %s", rsc->id, node->details->uname,
pcmk_is_set(rsc->flags, pe_rsc_managed)? "" : "(unmanaged)");
rsc->running_on = g_list_append(rsc->running_on, node);
if (rsc->variant == pe_native) {
node->details->running_rsc = g_list_append(node->details->running_rsc, rsc);
native_priority_to_node(rsc, node);
}
if (rsc->variant == pe_native && node->details->maintenance) {
pe__clear_resource_flags(rsc, pe_rsc_managed);
}
if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
pe_resource_t *p = rsc->parent;
pe_rsc_info(rsc, "resource %s isn't managed", rsc->id);
resource_location(rsc, node, INFINITY, "not_managed_default", data_set);
while(p && node->details->online) {
/* add without the additional location constraint */
p->running_on = g_list_append(p->running_on, node);
p = p->parent;
}
return;
}
if (is_multiply_active(rsc)) {
switch (rsc->recovery_type) {
case recovery_stop_only:
{
GHashTableIter gIter;
pe_node_t *local_node = NULL;
/* make sure it doesn't come up again */
if (rsc->allowed_nodes != NULL) {
g_hash_table_destroy(rsc->allowed_nodes);
}
rsc->allowed_nodes = pe__node_list2table(data_set->nodes);
g_hash_table_iter_init(&gIter, rsc->allowed_nodes);
while (g_hash_table_iter_next(&gIter, NULL, (void **)&local_node)) {
local_node->weight = -INFINITY;
}
}
break;
case recovery_stop_start:
break;
case recovery_block:
pe__clear_resource_flags(rsc, pe_rsc_managed);
pe__set_resource_flags(rsc, pe_rsc_block);
/* If the resource belongs to a group or bundle configured with
* multiple-active=block, block the entire entity.
*/
if (rsc->parent
&& (rsc->parent->variant == pe_group || rsc->parent->variant == pe_container)
&& rsc->parent->recovery_type == recovery_block) {
GListPtr gIter = rsc->parent->children;
for (; gIter != NULL; gIter = gIter->next) {
pe_resource_t *child = (pe_resource_t *) gIter->data;
pe__clear_resource_flags(child, pe_rsc_managed);
pe__set_resource_flags(child, pe_rsc_block);
}
}
break;
}
crm_debug("%s is active on multiple nodes including %s: %s",
rsc->id, node->details->uname,
recovery2text(rsc->recovery_type));
} else {
pe_rsc_trace(rsc, "Resource %s is active on: %s", rsc->id, node->details->uname);
}
if (rsc->parent != NULL) {
native_add_running(rsc->parent, node, data_set);
}
}
static void
recursive_clear_unique(pe_resource_t *rsc)
{
pe__clear_resource_flags(rsc, pe_rsc_unique);
add_hash_param(rsc->meta, XML_RSC_ATTR_UNIQUE, XML_BOOLEAN_FALSE);
for (GList *child = rsc->children; child != NULL; child = child->next) {
recursive_clear_unique((pe_resource_t *) child->data);
}
}
gboolean
native_unpack(pe_resource_t * rsc, pe_working_set_t * data_set)
{
pe_resource_t *parent = uber_parent(rsc);
native_variant_data_t *native_data = NULL;
const char *standard = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
uint32_t ra_caps = pcmk_get_ra_caps(standard);
pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
native_data = calloc(1, sizeof(native_variant_data_t));
rsc->variant_opaque = native_data;
// Only some agent standards support unique and promotable clones
if (!pcmk_is_set(ra_caps, pcmk_ra_cap_unique)
&& pcmk_is_set(rsc->flags, pe_rsc_unique) && pe_rsc_is_clone(parent)) {
/* @COMPAT We should probably reject this situation as an error (as we
* do for promotable below) rather than warn and convert, but that would
* be a backward-incompatible change that we should probably do with a
* transform at a schema major version bump.
*/
pe__force_anon(standard, parent, rsc->id, data_set);
/* Clear globally-unique on the parent and all its descendents unpacked
* so far (clearing the parent should make any future children unpacking
* correct). We have to clear this resource explicitly because it isn't
* hooked into the parent's children yet.
*/
recursive_clear_unique(parent);
recursive_clear_unique(rsc);
}
if (!pcmk_is_set(ra_caps, pcmk_ra_cap_promotable)
&& pcmk_is_set(parent->flags, pe_rsc_promotable)) {
pe_err("Resource %s is of type %s and therefore "
"cannot be used as a promotable clone resource",
rsc->id, standard);
return FALSE;
}
return TRUE;
}
static bool
rsc_is_on_node(pe_resource_t *rsc, const pe_node_t *node, int flags)
{
pe_rsc_trace(rsc, "Checking whether %s is on %s",
rsc->id, node->details->uname);
if (pcmk_is_set(flags, pe_find_current) && rsc->running_on) {
for (GListPtr iter = rsc->running_on; iter; iter = iter->next) {
pe_node_t *loc = (pe_node_t *) iter->data;
if (loc->details == node->details) {
return TRUE;
}
}
} else if (pcmk_is_set(flags, pe_find_inactive)
&& (rsc->running_on == NULL)) {
return TRUE;
} else if (!pcmk_is_set(flags, pe_find_current) && rsc->allocated_to
&& (rsc->allocated_to->details == node->details)) {
return TRUE;
}
return FALSE;
}
pe_resource_t *
native_find_rsc(pe_resource_t * rsc, const char *id, const pe_node_t *on_node,
int flags)
{
bool match = FALSE;
pe_resource_t *result = NULL;
CRM_CHECK(id && rsc && rsc->id, return NULL);
if (flags & pe_find_clone) {
const char *rid = ID(rsc->xml);
if (!pe_rsc_is_clone(uber_parent(rsc))) {
match = FALSE;
} else if (!strcmp(id, rsc->id) || pcmk__str_eq(id, rid, pcmk__str_casei)) {
match = TRUE;
}
} else if (!strcmp(id, rsc->id)) {
match = TRUE;
} else if (pcmk_is_set(flags, pe_find_renamed)
&& rsc->clone_name && strcmp(rsc->clone_name, id) == 0) {
match = TRUE;
} else if (pcmk_is_set(flags, pe_find_any)
|| (pcmk_is_set(flags, pe_find_anon)
&& !pcmk_is_set(rsc->flags, pe_rsc_unique))) {
match = pe_base_name_eq(rsc, id);
}
if (match && on_node) {
bool match_node = rsc_is_on_node(rsc, on_node, flags);
if (match_node == FALSE) {
match = FALSE;
}
}
if (match) {
return rsc;
}
for (GListPtr gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
pe_resource_t *child = (pe_resource_t *) gIter->data;
result = rsc->fns->find_rsc(child, id, on_node, flags);
if (result) {
return result;
}
}
return NULL;
}
char *
native_parameter(pe_resource_t * rsc, pe_node_t * node, gboolean create, const char *name,
pe_working_set_t * data_set)
{
char *value_copy = NULL;
const char *value = NULL;
GHashTable *hash = NULL;
GHashTable *local_hash = NULL;
CRM_CHECK(rsc != NULL, return NULL);
CRM_CHECK(name != NULL && strlen(name) != 0, return NULL);
pe_rsc_trace(rsc, "Looking up %s in %s", name, rsc->id);
if (create || g_hash_table_size(rsc->parameters) == 0) {
if (node != NULL) {
pe_rsc_trace(rsc, "Creating hash with node %s", node->details->uname);
} else {
pe_rsc_trace(rsc, "Creating default hash");
}
local_hash = crm_str_table_new();
get_rsc_attributes(local_hash, rsc, node, data_set);
hash = local_hash;
} else {
hash = rsc->parameters;
}
value = g_hash_table_lookup(hash, name);
if (value == NULL) {
/* try meta attributes instead */
value = g_hash_table_lookup(rsc->meta, name);
}
if (value != NULL) {
value_copy = strdup(value);
}
if (local_hash != NULL) {
g_hash_table_destroy(local_hash);
}
return value_copy;
}
gboolean
native_active(pe_resource_t * rsc, gboolean all)
{
for (GList *gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) {
pe_node_t *a_node = (pe_node_t *) gIter->data;
if (a_node->details->unclean) {
pe_rsc_trace(rsc, "Resource %s: node %s is unclean",
rsc->id, a_node->details->uname);
return TRUE;
} else if (a_node->details->online == FALSE) {
pe_rsc_trace(rsc, "Resource %s: node %s is offline",
rsc->id, a_node->details->uname);
} else {
pe_rsc_trace(rsc, "Resource %s active on %s",
rsc->id, a_node->details->uname);
return TRUE;
}
}
return FALSE;
}
struct print_data_s {
long options;
void *print_data;
};
static const char *
native_pending_state(pe_resource_t * rsc)
{
const char *pending_state = NULL;
if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_START, pcmk__str_casei)) {
pending_state = "Starting";
} else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_STOP, pcmk__str_casei)) {
pending_state = "Stopping";
} else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_MIGRATE, pcmk__str_casei)) {
pending_state = "Migrating";
} else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_MIGRATED, pcmk__str_casei)) {
/* Work might be done in here. */
pending_state = "Migrating";
} else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_PROMOTE, pcmk__str_casei)) {
pending_state = "Promoting";
} else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_DEMOTE, pcmk__str_casei)) {
pending_state = "Demoting";
}
return pending_state;
}
static const char *
native_pending_task(pe_resource_t * rsc)
{
const char *pending_task = NULL;
if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_STATUS, pcmk__str_casei)) {
pending_task = "Monitoring";
/* Pending probes are not printed, even if pending
* operations are requested. If someone ever requests that
* behavior, uncomment this and the corresponding part of
* unpack.c:unpack_rsc_op().
*/
/*
} else if (pcmk__str_eq(rsc->pending_task, "probe", pcmk__str_casei)) {
pending_task = "Checking";
*/
}
return pending_task;
}
static enum rsc_role_e
native_displayable_role(pe_resource_t *rsc)
{
enum rsc_role_e role = rsc->role;
if ((role == RSC_ROLE_STARTED)
&& pcmk_is_set(uber_parent(rsc)->flags, pe_rsc_promotable)) {
role = RSC_ROLE_SLAVE;
}
return role;
}
static const char *
native_displayable_state(pe_resource_t *rsc, long options)
{
const char *rsc_state = NULL;
if (options & pe_print_pending) {
rsc_state = native_pending_state(rsc);
}
if (rsc_state == NULL) {
rsc_state = role2text(native_displayable_role(rsc));
}
return rsc_state;
}
static void
native_print_xml(pe_resource_t * rsc, const char *pre_text, long options, void *print_data)
{
const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
const char *rsc_state = native_displayable_state(rsc, options);
const char *target_role = NULL;
/* resource information. */
status_print("%s<resource ", pre_text);
status_print("id=\"%s\" ", rsc_printable_id(rsc));
status_print("resource_agent=\"%s%s%s:%s\" ",
class,
prov ? "::" : "", prov ? prov : "", crm_element_value(rsc->xml, XML_ATTR_TYPE));
status_print("role=\"%s\" ", rsc_state);
if (rsc->meta) {
target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
}
if (target_role) {
status_print("target_role=\"%s\" ", target_role);
}
status_print("active=\"%s\" ", pcmk__btoa(rsc->fns->active(rsc, TRUE)));
status_print("orphaned=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_orphan));
status_print("blocked=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_block));
status_print("managed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_managed));
status_print("failed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_failed));
status_print("failure_ignored=\"%s\" ",
pe__rsc_bool_str(rsc, pe_rsc_failure_ignored));
status_print("nodes_running_on=\"%d\" ", g_list_length(rsc->running_on));
if (options & pe_print_pending) {
const char *pending_task = native_pending_task(rsc);
if (pending_task) {
status_print("pending=\"%s\" ", pending_task);
}
}
/* print out the nodes this resource is running on */
if (options & pe_print_rsconly) {
status_print("/>\n");
/* do nothing */
} else if (rsc->running_on != NULL) {
GListPtr gIter = rsc->running_on;
status_print(">\n");
for (; gIter != NULL; gIter = gIter->next) {
pe_node_t *node = (pe_node_t *) gIter->data;
status_print("%s <node name=\"%s\" id=\"%s\" cached=\"%s\"/>\n", pre_text,
node->details->uname, node->details->id,
pcmk__btoa(node->details->online == FALSE));
}
status_print("%s</resource>\n", pre_text);
} else {
status_print("/>\n");
}
}
// Append a flag to resource description string's flags list
static bool
add_output_flag(GString *s, const char *flag_desc, bool have_flags)
{
g_string_append(s, (have_flags? ", " : " ("));
g_string_append(s, flag_desc);
return true;
}
// Append a node name to resource description string's node list
static bool
add_output_node(GString *s, const char *node, bool have_nodes)
{
g_string_append(s, (have_nodes? " " : " [ "));
g_string_append(s, node);
return true;
}
/*!
* \internal
* \brief Create a string description of a resource
*
* \param[in] rsc Resource to describe
* \param[in] name Desired identifier for the resource
* \param[in] node If not NULL, node that resource is "on"
* \param[in] options Bitmask of pe_print_*
* \param[in] target_role Resource's target role
* \param[in] show_nodes Whether to display nodes when multiply active
*
* \return Newly allocated string description of resource
* \note Caller must free the result with g_free().
*/
gchar *
pcmk__native_output_string(pe_resource_t *rsc, const char *name, pe_node_t *node,
long options, const char *target_role, bool show_nodes)
{
const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
const char *provider = NULL;
const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
gchar *retval = NULL;
GString *outstr = NULL;
bool have_flags = false;
if (rsc->variant != pe_native) {
return NULL;
}
CRM_CHECK(name != NULL, name = "unknown");
CRM_CHECK(kind != NULL, kind = "unknown");
CRM_CHECK(class != NULL, class = "unknown");
if (pcmk_is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) {
provider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
}
if ((node == NULL) && (rsc->lock_node != NULL)) {
node = rsc->lock_node;
}
if (pcmk_is_set(options, pe_print_rsconly)
|| pcmk__list_of_multiple(rsc->running_on)) {
node = NULL;
}
// We need a string of at least this size
outstr = g_string_sized_new(strlen(name) + strlen(class) + strlen(kind)
+ (provider? (strlen(provider) + 2) : 0)
+ (node? strlen(node->details->uname) + 1 : 0)
+ 11);
// Resource name and agent
g_string_printf(outstr, "%s\t(%s%s%s:%s):\t", name, class,
/* @COMPAT This should be a single ':' (see CLBZ#5395) but
* to avoid breaking anything relying on it, we're keeping
* it like this until the next minor version bump.
*/
(provider? "::" : ""), (provider? provider : ""), kind);
// State on node
if (pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
g_string_append(outstr, " ORPHANED");
}
if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
enum rsc_role_e role = native_displayable_role(rsc);
if (role > RSC_ROLE_SLAVE) {
g_string_append_printf(outstr, " FAILED %s", role2text(role));
} else {
g_string_append(outstr, " FAILED");
}
} else {
g_string_append_printf(outstr, " %s", native_displayable_state(rsc, options));
}
if (node) {
g_string_append_printf(outstr, " %s", node->details->uname);
}
// Flags, as: (<flag> [...])
if (node && !(node->details->online) && node->details->unclean) {
have_flags = add_output_flag(outstr, "UNCLEAN", have_flags);
}
if (node && (node == rsc->lock_node)) {
have_flags = add_output_flag(outstr, "LOCKED", have_flags);
}
if (pcmk_is_set(options, pe_print_pending)) {
const char *pending_task = native_pending_task(rsc);
if (pending_task) {
have_flags = add_output_flag(outstr, pending_task, have_flags);
}
}
if (target_role) {
enum rsc_role_e target_role_e = text2role(target_role);
/* Only show target role if it limits our abilities (i.e. ignore
* Started, as it is the default anyways, and doesn't prevent the
* resource from becoming Master).
*/
if (target_role_e == RSC_ROLE_STOPPED) {
have_flags = add_output_flag(outstr, "disabled", have_flags);
} else if (pcmk_is_set(uber_parent(rsc)->flags, pe_rsc_promotable)
&& target_role_e == RSC_ROLE_SLAVE) {
have_flags = add_output_flag(outstr, "target-role:", have_flags);
g_string_append(outstr, target_role);
}
}
if (pcmk_is_set(rsc->flags, pe_rsc_block)) {
have_flags = add_output_flag(outstr, "blocked", have_flags);
} else if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
have_flags = add_output_flag(outstr, "unmanaged", have_flags);
}
if (pcmk_is_set(rsc->flags, pe_rsc_failure_ignored)) {
have_flags = add_output_flag(outstr, "failure ignored", have_flags);
}
if (have_flags) {
g_string_append(outstr, ")");
}
// User-supplied description
if (pcmk_is_set(options, pe_print_rsconly)
|| pcmk__list_of_multiple(rsc->running_on)) {
const char *desc = crm_element_value(rsc->xml, XML_ATTR_DESC);
if (desc) {
g_string_append_printf(outstr, " %s", desc);
}
}
if (show_nodes && !pcmk_is_set(options, pe_print_rsconly)
&& pcmk__list_of_multiple(rsc->running_on)) {
bool have_nodes = false;
for (GList *iter = rsc->running_on; iter != NULL; iter = iter->next) {
pe_node_t *n = (pe_node_t *) iter->data;
have_nodes = add_output_node(outstr, n->details->uname, have_nodes);
}
if (have_nodes) {
g_string_append(outstr, " ]");
}
}
retval = outstr->str;
g_string_free(outstr, FALSE);
return retval;
}
int
pe__common_output_html(pcmk__output_t *out, pe_resource_t * rsc,
const char *name, pe_node_t *node, long options)
{
const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
const char *target_role = NULL;
xmlNodePtr list_node = NULL;
const char *cl = NULL;
CRM_ASSERT(rsc->variant == pe_native);
CRM_ASSERT(kind != NULL);
if (rsc->meta) {
const char *is_internal = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERNAL_RSC);
if (crm_is_true(is_internal)
&& !pcmk_is_set(options, pe_print_implicit)) {
crm_trace("skipping print of internal resource %s", rsc->id);
return pcmk_rc_no_output;
}
target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
}
if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
cl = "rsc-managed";
} else if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
cl = "rsc-failed";
} else if (rsc->variant == pe_native && (rsc->running_on == NULL)) {
cl = "rsc-failed";
} else if (pcmk__list_of_multiple(rsc->running_on)) {
cl = "rsc-multiple";
} else if (pcmk_is_set(rsc->flags, pe_rsc_failure_ignored)) {
cl = "rsc-failure-ignored";
} else {
cl = "rsc-ok";
}
{
gchar *s = pcmk__native_output_string(rsc, name, node, options,
target_role, true);
list_node = pcmk__output_create_html_node(out, "li", NULL, NULL, NULL);
pcmk_create_html_node(list_node, "span", NULL, cl, s);
g_free(s);
}
return pcmk_rc_ok;
}
int
pe__common_output_text(pcmk__output_t *out, pe_resource_t * rsc,
const char *name, pe_node_t *node, long options)
{
const char *target_role = NULL;
CRM_ASSERT(rsc->variant == pe_native);
if (rsc->meta) {
const char *is_internal = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERNAL_RSC);
if (crm_is_true(is_internal)
&& !pcmk_is_set(options, pe_print_implicit)) {
crm_trace("skipping print of internal resource %s", rsc->id);
return pcmk_rc_no_output;
}
target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
}
{
gchar *s = pcmk__native_output_string(rsc, name, node, options,
target_role, true);
out->list_item(out, NULL, "%s", s);
g_free(s);
}
return pcmk_rc_ok;
}
void
common_print(pe_resource_t * rsc, const char *pre_text, const char *name, pe_node_t *node, long options, void *print_data)
{
const char *target_role = NULL;
CRM_ASSERT(rsc->variant == pe_native);
if (rsc->meta) {
const char *is_internal = g_hash_table_lookup(rsc->meta,
XML_RSC_ATTR_INTERNAL_RSC);
if (crm_is_true(is_internal)
&& !pcmk_is_set(options, pe_print_implicit)) {
crm_trace("skipping print of internal resource %s", rsc->id);
return;
}
target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
}
if (options & pe_print_xml) {
native_print_xml(rsc, pre_text, options, print_data);
return;
}
if ((pre_text == NULL) && (options & pe_print_printf)) {
pre_text = " ";
}
if (options & pe_print_html) {
if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
status_print("<font color=\"yellow\">");
} else if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
status_print("<font color=\"red\">");
} else if (rsc->running_on == NULL) {
status_print("<font color=\"red\">");
} else if (pcmk__list_of_multiple(rsc->running_on)) {
status_print("<font color=\"orange\">");
} else if (pcmk_is_set(rsc->flags, pe_rsc_failure_ignored)) {
status_print("<font color=\"yellow\">");
} else {
status_print("<font color=\"green\">");
}
}
{
gchar *resource_s = pcmk__native_output_string(rsc, name, node, options,
target_role, false);
status_print("%s%s", (pre_text? pre_text : ""), resource_s);
g_free(resource_s);
}
#if CURSES_ENABLED
if (pcmk_is_set(options, pe_print_ncurses)
&& !pcmk_is_set(options, pe_print_rsconly)
&& !pcmk__list_of_multiple(rsc->running_on)) {
/* coverity[negative_returns] False positive */
move(-1, 0);
}
#endif
if (pcmk_is_set(options, pe_print_html)) {
status_print(" </font> ");
}
if (!pcmk_is_set(options, pe_print_rsconly)
&& pcmk__list_of_multiple(rsc->running_on)) {
GListPtr gIter = rsc->running_on;
int counter = 0;
if (options & pe_print_html) {
status_print("<ul>\n");
} else if ((options & pe_print_printf)
|| (options & pe_print_ncurses)) {
status_print("[");
}
for (; gIter != NULL; gIter = gIter->next) {
pe_node_t *n = (pe_node_t *) gIter->data;
counter++;
if (options & pe_print_html) {
status_print("<li>\n%s", n->details->uname);
} else if ((options & pe_print_printf)
|| (options & pe_print_ncurses)) {
status_print(" %s", n->details->uname);
} else if ((options & pe_print_log)) {
status_print("\t%d : %s", counter, n->details->uname);
} else {
status_print("%s", n->details->uname);
}
if (options & pe_print_html) {
status_print("</li>\n");
}
}
if (options & pe_print_html) {
status_print("</ul>\n");
} else if ((options & pe_print_printf)
|| (options & pe_print_ncurses)) {
status_print(" ]");
}
}
if (options & pe_print_html) {
status_print("<br/>\n");
} else if (options & pe_print_suppres_nl) {
/* nothing */
} else if ((options & pe_print_printf) || (options & pe_print_ncurses)) {
status_print("\n");
}
}
void
native_print(pe_resource_t * rsc, const char *pre_text, long options, void *print_data)
{
pe_node_t *node = NULL;
CRM_ASSERT(rsc->variant == pe_native);
if (options & pe_print_xml) {
native_print_xml(rsc, pre_text, options, print_data);
return;
}
node = pe__current_node(rsc);
if (node == NULL) {
// This is set only if a non-probe action is pending on this node
node = rsc->pending_node;
}
common_print(rsc, pre_text, rsc_printable_id(rsc), node, options, print_data);
}
-PCMK__OUTPUT_ARGS("primitive", "unsigned int", "pe_resource_t *", "GListPtr", "GListPtr")
+PCMK__OUTPUT_ARGS("primitive", "unsigned int", "pe_resource_t *", "GList *", "GList *")
int
pe__resource_xml(pcmk__output_t *out, va_list args)
{
unsigned int options = va_arg(args, unsigned int);
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
- GListPtr only_node G_GNUC_UNUSED = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *only_node G_GNUC_UNUSED = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
const char *rsc_state = native_displayable_state(rsc, options);
long is_print_pending = options & pe_print_pending;
char ra_name[LINE_MAX];
char *nodes_running_on = NULL;
char *priority = NULL;
int rc = pcmk_rc_no_output;
const char *target_role = NULL;
if (rsc->meta != NULL) {
target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
}
CRM_ASSERT(rsc->variant == pe_native);
if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
return pcmk_rc_no_output;
}
/* resource information. */
sprintf(ra_name, "%s%s%s:%s", class, prov ? "::" : "", prov ? prov : ""
, crm_element_value(rsc->xml, XML_ATTR_TYPE));
nodes_running_on = crm_itoa(g_list_length(rsc->running_on));
priority = crm_ftoa(rsc->priority);
rc = pe__name_and_nvpairs_xml(out, true, "resource", 12,
"id", rsc_printable_id(rsc),
"resource_agent", ra_name,
"role", rsc_state,
"target_role", target_role,
"active", pcmk__btoa(rsc->fns->active(rsc, TRUE)),
"orphaned", pe__rsc_bool_str(rsc, pe_rsc_orphan),
"blocked", pe__rsc_bool_str(rsc, pe_rsc_block),
"managed", pe__rsc_bool_str(rsc, pe_rsc_managed),
"failed", pe__rsc_bool_str(rsc, pe_rsc_failed),
"failure_ignored", pe__rsc_bool_str(rsc, pe_rsc_failure_ignored),
"nodes_running_on", nodes_running_on,
"pending", (is_print_pending? native_pending_task(rsc) : NULL));
free(priority);
free(nodes_running_on);
CRM_ASSERT(rc == pcmk_rc_ok);
if (rsc->running_on != NULL) {
- GListPtr gIter = rsc->running_on;
+ GList *gIter = rsc->running_on;
for (; gIter != NULL; gIter = gIter->next) {
pe_node_t *node = (pe_node_t *) gIter->data;
rc = pe__name_and_nvpairs_xml(out, false, "node", 3,
"name", node->details->uname,
"id", node->details->id,
"cached", pcmk__btoa(node->details->online));
CRM_ASSERT(rc == pcmk_rc_ok);
}
}
pcmk__output_xml_pop_parent(out);
return rc;
}
-PCMK__OUTPUT_ARGS("primitive", "unsigned int", "pe_resource_t *", "GListPtr", "GListPtr")
+PCMK__OUTPUT_ARGS("primitive", "unsigned int", "pe_resource_t *", "GList *", "GList *")
int
pe__resource_html(pcmk__output_t *out, va_list args)
{
unsigned int options = va_arg(args, unsigned int);
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
- GListPtr only_node G_GNUC_UNUSED = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *only_node G_GNUC_UNUSED = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
pe_node_t *node = pe__current_node(rsc);
if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
return pcmk_rc_no_output;
}
CRM_ASSERT(rsc->variant == pe_native);
if (node == NULL) {
// This is set only if a non-probe action is pending on this node
node = rsc->pending_node;
}
return pe__common_output_html(out, rsc, rsc_printable_id(rsc), node, options);
}
-PCMK__OUTPUT_ARGS("primitive", "unsigned int", "pe_resource_t *", "GListPtr", "GListPtr")
+PCMK__OUTPUT_ARGS("primitive", "unsigned int", "pe_resource_t *", "GList *", "GList *")
int
pe__resource_text(pcmk__output_t *out, va_list args)
{
unsigned int options = va_arg(args, unsigned int);
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
- GListPtr only_node G_GNUC_UNUSED = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *only_node G_GNUC_UNUSED = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
pe_node_t *node = pe__current_node(rsc);
CRM_ASSERT(rsc->variant == pe_native);
if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
return pcmk_rc_no_output;
}
if (node == NULL) {
// This is set only if a non-probe action is pending on this node
node = rsc->pending_node;
}
return pe__common_output_text(out, rsc, rsc_printable_id(rsc), node, options);
}
void
native_free(pe_resource_t * rsc)
{
pe_rsc_trace(rsc, "Freeing resource action list (not the data)");
common_free(rsc);
}
enum rsc_role_e
native_resource_state(const pe_resource_t * rsc, gboolean current)
{
enum rsc_role_e role = rsc->next_role;
if (current) {
role = rsc->role;
}
pe_rsc_trace(rsc, "%s state: %s", rsc->id, role2text(role));
return role;
}
/*!
* \internal
* \brief List nodes where a resource (or any of its children) is
*
* \param[in] rsc Resource to check
* \param[out] list List to add result to
* \param[in] current 0 = where known, 1 = running, 2 = running or pending
*
* \return If list contains only one node, that node
*/
pe_node_t *
native_location(const pe_resource_t *rsc, GList **list, int current)
{
pe_node_t *one = NULL;
GListPtr result = NULL;
if (rsc->children) {
GListPtr gIter = rsc->children;
for (; gIter != NULL; gIter = gIter->next) {
pe_resource_t *child = (pe_resource_t *) gIter->data;
child->fns->location(child, &result, current);
}
} else if (current) {
if (rsc->running_on) {
result = g_list_copy(rsc->running_on);
}
if ((current == 2) && rsc->pending_node
&& !pe_find_node_id(result, rsc->pending_node->details->id)) {
result = g_list_append(result, rsc->pending_node);
}
} else if (current == FALSE && rsc->allocated_to) {
result = g_list_append(NULL, rsc->allocated_to);
}
if (result && (result->next == NULL)) {
one = result->data;
}
if (list) {
GListPtr gIter = result;
for (; gIter != NULL; gIter = gIter->next) {
pe_node_t *node = (pe_node_t *) gIter->data;
if (*list == NULL || pe_find_node_id(*list, node->details->id) == NULL) {
*list = g_list_append(*list, node);
}
}
}
g_list_free(result);
return one;
}
static void
get_rscs_brief(GListPtr rsc_list, GHashTable * rsc_table, GHashTable * active_table)
{
GListPtr gIter = rsc_list;
for (; gIter != NULL; gIter = gIter->next) {
pe_resource_t *rsc = (pe_resource_t *) gIter->data;
const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
int offset = 0;
char buffer[LINE_MAX];
int *rsc_counter = NULL;
int *active_counter = NULL;
if (rsc->variant != pe_native) {
continue;
}
offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", class);
if (pcmk_is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) {
const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
offset += snprintf(buffer + offset, LINE_MAX - offset, "::%s", prov);
}
offset += snprintf(buffer + offset, LINE_MAX - offset, ":%s", kind);
CRM_LOG_ASSERT(offset > 0);
if (rsc_table) {
rsc_counter = g_hash_table_lookup(rsc_table, buffer);
if (rsc_counter == NULL) {
rsc_counter = calloc(1, sizeof(int));
*rsc_counter = 0;
g_hash_table_insert(rsc_table, strdup(buffer), rsc_counter);
}
(*rsc_counter)++;
}
if (active_table) {
GListPtr gIter2 = rsc->running_on;
for (; gIter2 != NULL; gIter2 = gIter2->next) {
pe_node_t *node = (pe_node_t *) gIter2->data;
GHashTable *node_table = NULL;
if (node->details->unclean == FALSE && node->details->online == FALSE) {
continue;
}
node_table = g_hash_table_lookup(active_table, node->details->uname);
if (node_table == NULL) {
node_table = crm_str_table_new();
g_hash_table_insert(active_table, strdup(node->details->uname), node_table);
}
active_counter = g_hash_table_lookup(node_table, buffer);
if (active_counter == NULL) {
active_counter = calloc(1, sizeof(int));
*active_counter = 0;
g_hash_table_insert(node_table, strdup(buffer), active_counter);
}
(*active_counter)++;
}
}
}
}
static void
destroy_node_table(gpointer data)
{
GHashTable *node_table = data;
if (node_table) {
g_hash_table_destroy(node_table);
}
}
void
print_rscs_brief(GListPtr rsc_list, const char *pre_text, long options,
void *print_data, gboolean print_all)
{
GHashTable *rsc_table = crm_str_table_new();
GHashTable *active_table = g_hash_table_new_full(crm_str_hash, g_str_equal,
free, destroy_node_table);
GHashTableIter hash_iter;
char *type = NULL;
int *rsc_counter = NULL;
get_rscs_brief(rsc_list, rsc_table, active_table);
g_hash_table_iter_init(&hash_iter, rsc_table);
while (g_hash_table_iter_next(&hash_iter, (gpointer *)&type, (gpointer *)&rsc_counter)) {
GHashTableIter hash_iter2;
char *node_name = NULL;
GHashTable *node_table = NULL;
int active_counter_all = 0;
g_hash_table_iter_init(&hash_iter2, active_table);
while (g_hash_table_iter_next(&hash_iter2, (gpointer *)&node_name, (gpointer *)&node_table)) {
int *active_counter = g_hash_table_lookup(node_table, type);
if (active_counter == NULL || *active_counter == 0) {
continue;
} else {
active_counter_all += *active_counter;
}
if (options & pe_print_rsconly) {
node_name = NULL;
}
if (options & pe_print_html) {
status_print("<li>\n");
}
if (print_all) {
status_print("%s%d/%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
active_counter ? *active_counter : 0,
rsc_counter ? *rsc_counter : 0, type,
active_counter && (*active_counter > 0) && node_name ? node_name : "");
} else {
status_print("%s%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
active_counter ? *active_counter : 0, type,
active_counter && (*active_counter > 0) && node_name ? node_name : "");
}
if (options & pe_print_html) {
status_print("</li>\n");
}
}
if (print_all && active_counter_all == 0) {
if (options & pe_print_html) {
status_print("<li>\n");
}
status_print("%s%d/%d\t(%s):\tActive\n", pre_text ? pre_text : "",
active_counter_all,
rsc_counter ? *rsc_counter : 0, type);
if (options & pe_print_html) {
status_print("</li>\n");
}
}
}
if (rsc_table) {
g_hash_table_destroy(rsc_table);
rsc_table = NULL;
}
if (active_table) {
g_hash_table_destroy(active_table);
active_table = NULL;
}
}
int
pe__rscs_brief_output(pcmk__output_t *out, GListPtr rsc_list, long options, gboolean print_all)
{
GHashTable *rsc_table = crm_str_table_new();
GHashTable *active_table = g_hash_table_new_full(crm_str_hash, g_str_equal,
free, destroy_node_table);
GListPtr sorted_rscs;
int rc = pcmk_rc_no_output;
get_rscs_brief(rsc_list, rsc_table, active_table);
/* Make a list of the rsc_table keys so that it can be sorted. This is to make sure
* output order stays consistent between systems.
*/
sorted_rscs = g_hash_table_get_keys(rsc_table);
sorted_rscs = g_list_sort(sorted_rscs, (GCompareFunc) strcmp);
for (GListPtr gIter = sorted_rscs; gIter; gIter = gIter->next) {
char *type = (char *) gIter->data;
int *rsc_counter = g_hash_table_lookup(rsc_table, type);
GHashTableIter hash_iter2;
char *node_name = NULL;
GHashTable *node_table = NULL;
int active_counter_all = 0;
g_hash_table_iter_init(&hash_iter2, active_table);
while (g_hash_table_iter_next(&hash_iter2, (gpointer *)&node_name, (gpointer *)&node_table)) {
int *active_counter = g_hash_table_lookup(node_table, type);
if (active_counter == NULL || *active_counter == 0) {
continue;
} else {
active_counter_all += *active_counter;
}
if (options & pe_print_rsconly) {
node_name = NULL;
}
if (print_all) {
out->list_item(out, NULL, " %d/%d\t(%s):\tActive %s",
*active_counter,
rsc_counter ? *rsc_counter : 0, type,
(*active_counter > 0) && node_name ? node_name : "");
} else {
out->list_item(out, NULL, " %d\t(%s):\tActive %s",
*active_counter, type,
(*active_counter > 0) && node_name ? node_name : "");
}
rc = pcmk_rc_ok;
}
if (print_all && active_counter_all == 0) {
out->list_item(out, NULL, " %d/%d\t(%s):\tActive",
active_counter_all,
rsc_counter ? *rsc_counter : 0, type);
rc = pcmk_rc_ok;
}
}
if (rsc_table) {
g_hash_table_destroy(rsc_table);
rsc_table = NULL;
}
if (active_table) {
g_hash_table_destroy(active_table);
active_table = NULL;
}
if (sorted_rscs) {
g_list_free(sorted_rscs);
}
return rc;
}
gboolean
pe__native_is_filtered(pe_resource_t *rsc, GListPtr only_rsc, gboolean check_parent)
{
if (pcmk__str_in_list(only_rsc, rsc_printable_id(rsc)) ||
pcmk__str_in_list(only_rsc, rsc->id)) {
return FALSE;
} else if (check_parent) {
pe_resource_t *up = uber_parent(rsc);
if (pe_rsc_is_bundled(rsc)) {
return up->parent->fns->is_filtered(up->parent, only_rsc, FALSE);
} else {
return up->fns->is_filtered(up, only_rsc, FALSE);
}
}
return TRUE;
}
diff --git a/lib/pengine/pe_output.c b/lib/pengine/pe_output.c
index ecb5c2cb56..3d2fc24a61 100644
--- a/lib/pengine/pe_output.c
+++ b/lib/pengine/pe_output.c
@@ -1,2038 +1,2038 @@
/*
* Copyright 2019-2020 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/iso8601_internal.h>
#include <crm/common/xml_internal.h>
#include <crm/msg_xml.h>
#include <crm/pengine/internal.h>
static char *
failed_action_string(xmlNodePtr xml_op) {
const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
int rc = crm_parse_int(crm_element_value(xml_op, XML_LRM_ATTR_RC), "0");
int status = crm_parse_int(crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS), "0");
const char *exit_reason = crm_element_value(xml_op, XML_LRM_ATTR_EXIT_REASON);
time_t last_change = 0;
if (crm_element_value_epoch(xml_op, XML_RSC_OP_LAST_CHANGE,
&last_change) == pcmk_ok) {
crm_time_t *crm_when = crm_time_new(NULL);
char *time_s = NULL;
char *buf = NULL;
crm_time_set_timet(crm_when, &last_change);
time_s = crm_time_as_string(crm_when, crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
buf = crm_strdup_printf("%s on %s '%s' (%d): call=%s, status='%s', "
"exitreason='%s', " XML_RSC_OP_LAST_CHANGE
"='%s', queued=%sms, exec=%sms",
op_key ? op_key : ID(xml_op),
crm_element_value(xml_op, XML_ATTR_UNAME),
services_ocf_exitcode_str(rc), rc,
crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
services_lrm_status_str(status),
exit_reason ? exit_reason : "none",
time_s,
crm_element_value(xml_op, XML_RSC_OP_T_QUEUE),
crm_element_value(xml_op, XML_RSC_OP_T_EXEC));
crm_time_free(crm_when);
free(time_s);
return buf;
} else {
return crm_strdup_printf("%s on %s '%s' (%d): call=%s, status=%s, exitreason='%s'",
op_key ? op_key : ID(xml_op),
crm_element_value(xml_op, XML_ATTR_UNAME),
services_ocf_exitcode_str(rc), rc,
crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
services_lrm_status_str(status),
exit_reason ? exit_reason : "none");
}
}
static const char *
get_cluster_stack(pe_working_set_t *data_set)
{
xmlNode *stack = get_xpath_object("//nvpair[@name='cluster-infrastructure']",
data_set->input, LOG_DEBUG);
return stack? crm_element_value(stack, XML_NVPAIR_ATTR_VALUE) : "unknown";
}
static char *
last_changed_string(const char *last_written, const char *user,
const char *client, const char *origin) {
if (last_written != NULL || user != NULL || client != NULL || origin != NULL) {
return crm_strdup_printf("%s%s%s%s%s%s%s",
last_written ? last_written : "",
user ? " by " : "",
user ? user : "",
client ? " via " : "",
client ? client : "",
origin ? " on " : "",
origin ? origin : "");
} else {
return strdup("");
}
}
static char *
op_history_string(xmlNode *xml_op, const char *task, const char *interval_ms_s,
int rc, gboolean print_timing) {
const char *call = crm_element_value(xml_op, XML_LRM_ATTR_CALLID);
char *interval_str = NULL;
char *buf = NULL;
if (interval_ms_s && !pcmk__str_eq(interval_ms_s, "0", pcmk__str_casei)) {
char *pair = pcmk_format_nvpair("interval", interval_ms_s, "ms");
interval_str = crm_strdup_printf(" %s", pair);
free(pair);
}
if (print_timing) {
char *last_change_str = NULL;
char *last_run_str = NULL;
char *exec_str = NULL;
char *queue_str = NULL;
const char *value = NULL;
time_t epoch = 0;
if ((crm_element_value_epoch(xml_op, XML_RSC_OP_LAST_CHANGE, &epoch) == pcmk_ok)
&& (epoch > 0)) {
char *time = pcmk_format_named_time(XML_RSC_OP_LAST_CHANGE, epoch);
last_change_str = crm_strdup_printf(" %s", time);
free(time);
}
if ((crm_element_value_epoch(xml_op, XML_RSC_OP_LAST_RUN, &epoch) == pcmk_ok)
&& (epoch > 0)) {
char *time = pcmk_format_named_time(XML_RSC_OP_LAST_RUN, epoch);
last_run_str = crm_strdup_printf(" %s", time);
free(time);
}
value = crm_element_value(xml_op, XML_RSC_OP_T_EXEC);
if (value) {
char *pair = pcmk_format_nvpair(XML_RSC_OP_T_EXEC, value, "ms");
exec_str = crm_strdup_printf(" %s", pair);
free(pair);
}
value = crm_element_value(xml_op, XML_RSC_OP_T_QUEUE);
if (value) {
char *pair = pcmk_format_nvpair(XML_RSC_OP_T_QUEUE, value, "ms");
queue_str = crm_strdup_printf(" %s", pair);
free(pair);
}
buf = crm_strdup_printf("(%s) %s:%s%s%s%s%s rc=%d (%s)", call, task,
interval_str ? interval_str : "",
last_change_str ? last_change_str : "",
last_run_str ? last_run_str : "",
exec_str ? exec_str : "",
queue_str ? queue_str : "",
rc, services_ocf_exitcode_str(rc));
if (last_change_str) {
free(last_change_str);
}
if (last_run_str) {
free(last_run_str);
}
if (exec_str) {
free(exec_str);
}
if (queue_str) {
free(queue_str);
}
} else {
buf = crm_strdup_printf("(%s) %s%s%s", call, task,
interval_str ? ":" : "",
interval_str ? interval_str : "");
}
if (interval_str) {
free(interval_str);
}
return buf;
}
static char *
resource_history_string(pe_resource_t *rsc, const char *rsc_id, gboolean all,
int failcount, time_t last_failure) {
char *buf = NULL;
if (rsc == NULL) {
buf = crm_strdup_printf("%s: orphan", rsc_id);
} else if (all || failcount || last_failure > 0) {
char *failcount_s = NULL;
char *lastfail_s = NULL;
if (failcount > 0) {
failcount_s = crm_strdup_printf(" %s=%d", PCMK__FAIL_COUNT_PREFIX,
failcount);
} else {
failcount_s = strdup("");
}
if (last_failure > 0) {
lastfail_s = crm_strdup_printf(" %s='%s'",
PCMK__LAST_FAILURE_PREFIX,
pcmk__epoch2str(&last_failure));
}
buf = crm_strdup_printf("%s: migration-threshold=%d%s%s",
rsc_id, rsc->migration_threshold, failcount_s,
lastfail_s? lastfail_s : "");
free(failcount_s);
free(lastfail_s);
} else {
buf = crm_strdup_printf("%s:", rsc_id);
}
return buf;
}
PCMK__OUTPUT_ARGS("cluster-summary", "pe_working_set_t *", "gboolean", "gboolean", "gboolean",
"gboolean", "gboolean", "gboolean")
int
pe__cluster_summary(pcmk__output_t *out, va_list args) {
pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
gboolean print_clone_detail = va_arg(args, gboolean);
gboolean show_stack = va_arg(args, gboolean);
gboolean show_dc = va_arg(args, gboolean);
gboolean show_times = va_arg(args, gboolean);
gboolean show_counts = va_arg(args, gboolean);
gboolean show_options = va_arg(args, gboolean);
int rc = pcmk_rc_no_output;
const char *stack_s = get_cluster_stack(data_set);
if (show_stack) {
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
out->message(out, "cluster-stack", stack_s);
}
/* Always print DC if none, even if not requested */
if (data_set->dc_node == NULL || show_dc) {
xmlNode *dc_version = get_xpath_object("//nvpair[@name='dc-version']",
data_set->input, LOG_DEBUG);
const char *dc_version_s = dc_version?
crm_element_value(dc_version, XML_NVPAIR_ATTR_VALUE)
: NULL;
const char *quorum = crm_element_value(data_set->input, XML_ATTR_HAVE_QUORUM);
char *dc_name = data_set->dc_node ? pe__node_display_name(data_set->dc_node, print_clone_detail) : NULL;
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
out->message(out, "cluster-dc", data_set->dc_node, quorum, dc_version_s, dc_name);
free(dc_name);
}
if (show_times) {
const char *last_written = crm_element_value(data_set->input, XML_CIB_ATTR_WRITTEN);
const char *user = crm_element_value(data_set->input, XML_ATTR_UPDATE_USER);
const char *client = crm_element_value(data_set->input, XML_ATTR_UPDATE_CLIENT);
const char *origin = crm_element_value(data_set->input, XML_ATTR_UPDATE_ORIG);
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
out->message(out, "cluster-times", last_written, user, client, origin);
}
if (show_counts) {
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
out->message(out, "cluster-counts", g_list_length(data_set->nodes),
data_set->ninstances, data_set->disabled_resources,
data_set->blocked_resources);
}
if (show_options) {
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
out->message(out, "cluster-options", data_set);
}
PCMK__OUTPUT_LIST_FOOTER(out, rc);
if (out->message(out, "maint-mode", data_set->flags) == pcmk_rc_ok) {
rc = pcmk_rc_ok;
}
return rc;
}
PCMK__OUTPUT_ARGS("cluster-summary", "pe_working_set_t *", "gboolean", "gboolean", "gboolean",
"gboolean", "gboolean", "gboolean")
int
pe__cluster_summary_html(pcmk__output_t *out, va_list args) {
pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
gboolean print_clone_detail = va_arg(args, gboolean);
gboolean show_stack = va_arg(args, gboolean);
gboolean show_dc = va_arg(args, gboolean);
gboolean show_times = va_arg(args, gboolean);
gboolean show_counts = va_arg(args, gboolean);
gboolean show_options = va_arg(args, gboolean);
int rc = pcmk_rc_no_output;
const char *stack_s = get_cluster_stack(data_set);
if (show_stack) {
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
out->message(out, "cluster-stack", stack_s);
}
/* Always print DC if none, even if not requested */
if (data_set->dc_node == NULL || show_dc) {
xmlNode *dc_version = get_xpath_object("//nvpair[@name='dc-version']",
data_set->input, LOG_DEBUG);
const char *dc_version_s = dc_version?
crm_element_value(dc_version, XML_NVPAIR_ATTR_VALUE)
: NULL;
const char *quorum = crm_element_value(data_set->input, XML_ATTR_HAVE_QUORUM);
char *dc_name = data_set->dc_node ? pe__node_display_name(data_set->dc_node, print_clone_detail) : NULL;
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
out->message(out, "cluster-dc", data_set->dc_node, quorum, dc_version_s, dc_name);
free(dc_name);
}
if (show_times) {
const char *last_written = crm_element_value(data_set->input, XML_CIB_ATTR_WRITTEN);
const char *user = crm_element_value(data_set->input, XML_ATTR_UPDATE_USER);
const char *client = crm_element_value(data_set->input, XML_ATTR_UPDATE_CLIENT);
const char *origin = crm_element_value(data_set->input, XML_ATTR_UPDATE_ORIG);
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
out->message(out, "cluster-times", last_written, user, client, origin);
}
if (show_counts) {
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
out->message(out, "cluster-counts", g_list_length(data_set->nodes),
data_set->ninstances, data_set->disabled_resources,
data_set->blocked_resources);
}
if (show_options) {
/* Kind of a hack - close the list we may have opened earlier in this
* function so we can put all the options into their own list. We
* only want to do this on HTML output, though.
*/
PCMK__OUTPUT_LIST_FOOTER(out, rc);
out->begin_list(out, NULL, NULL, "Config Options");
out->message(out, "cluster-options", data_set);
}
PCMK__OUTPUT_LIST_FOOTER(out, rc);
if (out->message(out, "maint-mode", data_set->flags) == pcmk_rc_ok) {
rc = pcmk_rc_ok;
}
return rc;
}
char *
pe__node_display_name(pe_node_t *node, bool print_detail)
{
char *node_name;
const char *node_host = NULL;
const char *node_id = NULL;
int name_len;
CRM_ASSERT((node != NULL) && (node->details != NULL) && (node->details->uname != NULL));
/* Host is displayed only if this is a guest node */
if (pe__is_guest_node(node)) {
pe_node_t *host_node = pe__current_node(node->details->remote_rsc);
if (host_node && host_node->details) {
node_host = host_node->details->uname;
}
if (node_host == NULL) {
node_host = ""; /* so we at least get "uname@" to indicate guest */
}
}
/* Node ID is displayed if different from uname and detail is requested */
if (print_detail && !pcmk__str_eq(node->details->uname, node->details->id, pcmk__str_casei)) {
node_id = node->details->id;
}
/* Determine name length */
name_len = strlen(node->details->uname) + 1;
if (node_host) {
name_len += strlen(node_host) + 1; /* "@node_host" */
}
if (node_id) {
name_len += strlen(node_id) + 3; /* + " (node_id)" */
}
/* Allocate and populate display name */
node_name = malloc(name_len);
CRM_ASSERT(node_name != NULL);
strcpy(node_name, node->details->uname);
if (node_host) {
strcat(node_name, "@");
strcat(node_name, node_host);
}
if (node_id) {
strcat(node_name, " (");
strcat(node_name, node_id);
strcat(node_name, ")");
}
return node_name;
}
int
pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name
, size_t pairs_count, ...)
{
xmlNodePtr xml_node = NULL;
va_list args;
CRM_ASSERT(tag_name != NULL);
xml_node = pcmk__output_xml_peek_parent(out);
CRM_ASSERT(xml_node != NULL);
xml_node = is_list
? create_xml_node(xml_node, tag_name)
: xmlNewChild(xml_node, NULL, (pcmkXmlStr) tag_name, NULL);
va_start(args, pairs_count);
while(pairs_count--) {
const char *param_name = va_arg(args, const char *);
const char *param_value = va_arg(args, const char *);
if (param_name && param_value) {
crm_xml_add(xml_node, param_name, param_value);
}
};
va_end(args);
if (is_list) {
pcmk__output_xml_push_parent(out, xml_node);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("ban", "pe_node_t *", "pe__location_t *", "gboolean")
int
pe__ban_html(pcmk__output_t *out, va_list args) {
pe_node_t *pe_node = va_arg(args, pe_node_t *);
pe__location_t *location = va_arg(args, pe__location_t *);
gboolean print_clone_detail = va_arg(args, gboolean);
char *node_name = pe__node_display_name(pe_node, print_clone_detail);
char *buf = crm_strdup_printf("%s\tprevents %s from running %son %s",
location->id, location->rsc_lh->id,
location->role_filter == RSC_ROLE_MASTER ? "as Master " : "",
node_name);
pcmk__output_create_html_node(out, "li", NULL, NULL, buf);
free(node_name);
free(buf);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("ban", "pe_node_t *", "pe__location_t *", "gboolean")
int
pe__ban_text(pcmk__output_t *out, va_list args) {
pe_node_t *pe_node = va_arg(args, pe_node_t *);
pe__location_t *location = va_arg(args, pe__location_t *);
gboolean print_clone_detail = va_arg(args, gboolean);
char *node_name = pe__node_display_name(pe_node, print_clone_detail);
out->list_item(out, NULL, "%s\tprevents %s from running %son %s",
location->id, location->rsc_lh->id,
location->role_filter == RSC_ROLE_MASTER ? "as Master " : "",
node_name);
free(node_name);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("ban", "pe_node_t *", "pe__location_t *", "gboolean")
int
pe__ban_xml(pcmk__output_t *out, va_list args) {
pe_node_t *pe_node = va_arg(args, pe_node_t *);
pe__location_t *location = va_arg(args, pe__location_t *);
gboolean print_clone_detail G_GNUC_UNUSED = va_arg(args, gboolean);
char *weight_s = crm_itoa(pe_node->weight);
pcmk__output_create_xml_node(out, "ban",
"id", location->id,
"resource", location->rsc_lh->id,
"node", pe_node->details->uname,
"weight", weight_s,
"master_only", pcmk__btoa(location->role_filter == RSC_ROLE_MASTER),
NULL);
free(weight_s);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("cluster-counts", "unsigned int", "int", "int", "int")
int
pe__cluster_counts_html(pcmk__output_t *out, va_list args) {
xmlNodePtr nodes_node = pcmk__output_create_xml_node(out, "li", NULL);
xmlNodePtr resources_node = pcmk__output_create_xml_node(out, "li", NULL);
unsigned int nnodes = va_arg(args, unsigned int);
int nresources = va_arg(args, int);
int ndisabled = va_arg(args, int);
int nblocked = va_arg(args, int);
char *nnodes_str = crm_strdup_printf("%d node%s configured",
nnodes, pcmk__plural_s(nnodes));
pcmk_create_html_node(nodes_node, "span", NULL, NULL, nnodes_str);
free(nnodes_str);
if (ndisabled && nblocked) {
char *s = crm_strdup_printf("%d resource instance%s configured (%d ",
nresources, pcmk__plural_s(nresources),
ndisabled);
pcmk_create_html_node(resources_node, "span", NULL, NULL, s);
free(s);
pcmk_create_html_node(resources_node, "span", NULL, "bold", "DISABLED");
s = crm_strdup_printf(", %d ", nblocked);
pcmk_create_html_node(resources_node, "span", NULL, NULL, s);
free(s);
pcmk_create_html_node(resources_node, "span", NULL, "bold", "BLOCKED");
pcmk_create_html_node(resources_node, "span", NULL, NULL,
" from further action due to failure)");
} else if (ndisabled && !nblocked) {
char *s = crm_strdup_printf("%d resource instance%s configured (%d ",
nresources, pcmk__plural_s(nresources),
ndisabled);
pcmk_create_html_node(resources_node, "span", NULL, NULL, s);
free(s);
pcmk_create_html_node(resources_node, "span", NULL, "bold", "DISABLED");
pcmk_create_html_node(resources_node, "span", NULL, NULL, ")");
} else if (!ndisabled && nblocked) {
char *s = crm_strdup_printf("%d resource instance%s configured (%d ",
nresources, pcmk__plural_s(nresources),
nblocked);
pcmk_create_html_node(resources_node, "span", NULL, NULL, s);
free(s);
pcmk_create_html_node(resources_node, "span", NULL, "bold", "BLOCKED");
pcmk_create_html_node(resources_node, "span", NULL, NULL,
" from further action due to failure)");
} else {
char *s = crm_strdup_printf("%d resource instance%s configured",
nresources, pcmk__plural_s(nresources));
pcmk_create_html_node(resources_node, "span", NULL, NULL, s);
free(s);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("cluster-counts", "unsigned int", "int", "int", "int")
int
pe__cluster_counts_text(pcmk__output_t *out, va_list args) {
unsigned int nnodes = va_arg(args, unsigned int);
int nresources = va_arg(args, int);
int ndisabled = va_arg(args, int);
int nblocked = va_arg(args, int);
out->list_item(out, NULL, "%d node%s configured",
nnodes, pcmk__plural_s(nnodes));
if (ndisabled && nblocked) {
out->list_item(out, NULL, "%d resource instance%s configured "
"(%d DISABLED, %d BLOCKED from "
"further action due to failure)",
nresources, pcmk__plural_s(nresources), ndisabled,
nblocked);
} else if (ndisabled && !nblocked) {
out->list_item(out, NULL, "%d resource instance%s configured "
"(%d DISABLED)",
nresources, pcmk__plural_s(nresources), ndisabled);
} else if (!ndisabled && nblocked) {
out->list_item(out, NULL, "%d resource instance%s configured "
"(%d BLOCKED from further action "
"due to failure)",
nresources, pcmk__plural_s(nresources), nblocked);
} else {
out->list_item(out, NULL, "%d resource instance%s configured",
nresources, pcmk__plural_s(nresources));
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("cluster-counts", "unsigned int", "int", "int", "int")
int
pe__cluster_counts_xml(pcmk__output_t *out, va_list args) {
xmlNodePtr nodes_node = pcmk__output_create_xml_node(out, "nodes_configured", NULL);
xmlNodePtr resources_node = pcmk__output_create_xml_node(out, "resources_configured", NULL);
unsigned int nnodes = va_arg(args, unsigned int);
int nresources = va_arg(args, int);
int ndisabled = va_arg(args, int);
int nblocked = va_arg(args, int);
char *s = crm_itoa(nnodes);
crm_xml_add(nodes_node, "number", s);
free(s);
s = crm_itoa(nresources);
crm_xml_add(resources_node, "number", s);
free(s);
s = crm_itoa(ndisabled);
crm_xml_add(resources_node, "disabled", s);
free(s);
s = crm_itoa(nblocked);
crm_xml_add(resources_node, "blocked", s);
free(s);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("cluster-dc", "pe_node_t *", "const char *", "const char *", "char *")
int
pe__cluster_dc_html(pcmk__output_t *out, va_list args) {
xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
pe_node_t *dc = va_arg(args, pe_node_t *);
const char *quorum = va_arg(args, const char *);
const char *dc_version_s = va_arg(args, const char *);
char *dc_name = va_arg(args, char *);
pcmk_create_html_node(node, "span", NULL, "bold", "Current DC: ");
if (dc) {
if (crm_is_true(quorum)) {
char *buf = crm_strdup_printf("%s (version %s) - partition with quorum",
dc_name, dc_version_s ? dc_version_s : "unknown");
pcmk_create_html_node(node, "span", NULL, NULL, buf);
free(buf);
} else {
char *buf = crm_strdup_printf("%s (version %s) - partition",
dc_name, dc_version_s ? dc_version_s : "unknown");
pcmk_create_html_node(node, "span", NULL, NULL, buf);
free(buf);
pcmk_create_html_node(node, "span", NULL, "warning", "WITHOUT");
pcmk_create_html_node(node, "span", NULL, NULL, "quorum");
}
} else {
pcmk_create_html_node(node ,"span", NULL, "warning", "NONE");
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("cluster-dc", "pe_node_t *", "const char *", "const char *", "char *")
int
pe__cluster_dc_text(pcmk__output_t *out, va_list args) {
pe_node_t *dc = va_arg(args, pe_node_t *);
const char *quorum = va_arg(args, const char *);
const char *dc_version_s = va_arg(args, const char *);
char *dc_name = va_arg(args, char *);
if (dc) {
out->list_item(out, "Current DC", "%s (version %s) - partition %s quorum",
dc_name, dc_version_s ? dc_version_s : "unknown",
crm_is_true(quorum) ? "with" : "WITHOUT");
} else {
out->list_item(out, "Current DC", "NONE");
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("cluster-dc", "pe_node_t *", "const char *", "const char *", "char *")
int
pe__cluster_dc_xml(pcmk__output_t *out, va_list args) {
pe_node_t *dc = va_arg(args, pe_node_t *);
const char *quorum = va_arg(args, const char *);
const char *dc_version_s = va_arg(args, const char *);
char *dc_name G_GNUC_UNUSED = va_arg(args, char *);
if (dc) {
pcmk__output_create_xml_node(out, "current_dc",
"present", "true",
"version", dc_version_s ? dc_version_s : "",
"name", dc->details->uname,
"id", dc->details->id,
"with_quorum", pcmk__btoa(crm_is_true(quorum)),
NULL);
} else {
pcmk__output_create_xml_node(out, "current_dc",
"present", "false",
NULL);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("maint-mode", "unsigned long long int")
int
pe__cluster_maint_mode_text(pcmk__output_t *out, va_list args) {
unsigned long long flags = va_arg(args, unsigned long long);
if (pcmk_is_set(flags, pe_flag_maintenance_mode)) {
fprintf(out->dest, "\n *** Resource management is DISABLED ***");
fprintf(out->dest, "\n The cluster will not attempt to start, stop or recover services");
fprintf(out->dest, "\n");
return pcmk_rc_ok;
} else if (pcmk_is_set(flags, pe_flag_stop_everything)) {
fprintf(out->dest, "\n *** Resource management is DISABLED ***");
fprintf(out->dest, "\n The cluster will keep all resources stopped");
fprintf(out->dest, "\n");
return pcmk_rc_ok;
} else {
return pcmk_rc_no_output;
}
}
PCMK__OUTPUT_ARGS("cluster-options", "pe_working_set_t *")
int
pe__cluster_options_html(pcmk__output_t *out, va_list args) {
pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
out->list_item(out, NULL, "STONITH of failed nodes %s",
pcmk_is_set(data_set->flags, pe_flag_stonith_enabled) ? "enabled" : "disabled");
out->list_item(out, NULL, "Cluster is %s",
pcmk_is_set(data_set->flags, pe_flag_symmetric_cluster) ? "symmetric" : "asymmetric");
switch (data_set->no_quorum_policy) {
case no_quorum_freeze:
out->list_item(out, NULL, "No quorum policy: Freeze resources");
break;
case no_quorum_stop:
out->list_item(out, NULL, "No quorum policy: Stop ALL resources");
break;
case no_quorum_demote:
out->list_item(out, NULL, "No quorum policy: Demote promotable "
"resources and stop all other resources");
break;
case no_quorum_ignore:
out->list_item(out, NULL, "No quorum policy: Ignore");
break;
case no_quorum_suicide:
out->list_item(out, NULL, "No quorum policy: Suicide");
break;
}
if (pcmk_is_set(data_set->flags, pe_flag_maintenance_mode)) {
xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
pcmk_create_html_node(node, "span", NULL, NULL, "Resource management: ");
pcmk_create_html_node(node, "span", NULL, "bold", "DISABLED");
pcmk_create_html_node(node, "span", NULL, NULL,
" (the cluster will not attempt to start, stop, or recover services)");
} else if (pcmk_is_set(data_set->flags, pe_flag_stop_everything)) {
xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
pcmk_create_html_node(node, "span", NULL, NULL, "Resource management: ");
pcmk_create_html_node(node, "span", NULL, "bold", "STOPPED");
pcmk_create_html_node(node, "span", NULL, NULL,
" (the cluster will keep all resources stopped)");
} else {
out->list_item(out, NULL, "Resource management: enabled");
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("cluster-options", "pe_working_set_t *")
int
pe__cluster_options_log(pcmk__output_t *out, va_list args) {
pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
if (pcmk_is_set(data_set->flags, pe_flag_maintenance_mode)) {
out->info(out, "Resource management is DISABLED. The cluster will not attempt to start, stop or recover services.");
return pcmk_rc_ok;
} else if (pcmk_is_set(data_set->flags, pe_flag_stop_everything)) {
out->info(out, "Resource management is DISABLED. The cluster has stopped all resources.");
return pcmk_rc_ok;
} else {
return pcmk_rc_no_output;
}
}
PCMK__OUTPUT_ARGS("cluster-options", "pe_working_set_t *")
int
pe__cluster_options_text(pcmk__output_t *out, va_list args) {
pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
out->list_item(out, NULL, "STONITH of failed nodes %s",
pcmk_is_set(data_set->flags, pe_flag_stonith_enabled) ? "enabled" : "disabled");
out->list_item(out, NULL, "Cluster is %s",
pcmk_is_set(data_set->flags, pe_flag_symmetric_cluster) ? "symmetric" : "asymmetric");
switch (data_set->no_quorum_policy) {
case no_quorum_freeze:
out->list_item(out, NULL, "No quorum policy: Freeze resources");
break;
case no_quorum_stop:
out->list_item(out, NULL, "No quorum policy: Stop ALL resources");
break;
case no_quorum_demote:
out->list_item(out, NULL, "No quorum policy: Demote promotable "
"resources and stop all other resources");
break;
case no_quorum_ignore:
out->list_item(out, NULL, "No quorum policy: Ignore");
break;
case no_quorum_suicide:
out->list_item(out, NULL, "No quorum policy: Suicide");
break;
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("cluster-options", "pe_working_set_t *")
int
pe__cluster_options_xml(pcmk__output_t *out, va_list args) {
pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
const char *no_quorum_policy = NULL;
switch (data_set->no_quorum_policy) {
case no_quorum_freeze:
no_quorum_policy = "freeze";
break;
case no_quorum_stop:
no_quorum_policy = "stop";
break;
case no_quorum_demote:
no_quorum_policy = "demote";
break;
case no_quorum_ignore:
no_quorum_policy = "ignore";
break;
case no_quorum_suicide:
no_quorum_policy = "suicide";
break;
}
pcmk__output_create_xml_node(out, "cluster_options",
"stonith-enabled", pcmk__btoa(pcmk_is_set(data_set->flags, pe_flag_stonith_enabled)),
"symmetric-cluster", pcmk__btoa(pcmk_is_set(data_set->flags, pe_flag_symmetric_cluster)),
"no-quorum-policy", no_quorum_policy,
"maintenance-mode", pcmk__btoa(pcmk_is_set(data_set->flags, pe_flag_maintenance_mode)),
"stop-all-resources", pcmk__btoa(pcmk_is_set(data_set->flags, pe_flag_stop_everything)),
NULL);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("cluster-stack", "const char *")
int
pe__cluster_stack_html(pcmk__output_t *out, va_list args) {
xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
const char *stack_s = va_arg(args, const char *);
pcmk_create_html_node(node, "span", NULL, "bold", "Stack: ");
pcmk_create_html_node(node, "span", NULL, NULL, stack_s);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("cluster-stack", "const char *")
int
pe__cluster_stack_text(pcmk__output_t *out, va_list args) {
const char *stack_s = va_arg(args, const char *);
out->list_item(out, "Stack", "%s", stack_s);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("cluster-stack", "const char *")
int
pe__cluster_stack_xml(pcmk__output_t *out, va_list args) {
const char *stack_s = va_arg(args, const char *);
pcmk__output_create_xml_node(out, "stack",
"type", stack_s,
NULL);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("cluster-times", "const char *", "const char *", "const char *", "const char *")
int
pe__cluster_times_html(pcmk__output_t *out, va_list args) {
xmlNodePtr updated_node = pcmk__output_create_xml_node(out, "li", NULL);
xmlNodePtr changed_node = pcmk__output_create_xml_node(out, "li", NULL);
const char *last_written = va_arg(args, const char *);
const char *user = va_arg(args, const char *);
const char *client = va_arg(args, const char *);
const char *origin = va_arg(args, const char *);
char *buf = last_changed_string(last_written, user, client, origin);
pcmk_create_html_node(updated_node, "span", NULL, "bold", "Last updated: ");
pcmk_create_html_node(updated_node, "span", NULL, NULL,
pcmk__epoch2str(NULL));
pcmk_create_html_node(changed_node, "span", NULL, "bold", "Last change: ");
pcmk_create_html_node(changed_node, "span", NULL, NULL, buf);
free(buf);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("cluster-times", "const char *", "const char *", "const char *", "const char *")
int
pe__cluster_times_xml(pcmk__output_t *out, va_list args) {
const char *last_written = va_arg(args, const char *);
const char *user = va_arg(args, const char *);
const char *client = va_arg(args, const char *);
const char *origin = va_arg(args, const char *);
pcmk__output_create_xml_node(out, "last_update",
"time", pcmk__epoch2str(NULL),
NULL);
pcmk__output_create_xml_node(out, "last_change",
"time", last_written ? last_written : "",
"user", user ? user : "",
"client", client ? client : "",
"origin", origin ? origin : "",
NULL);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("cluster-times", "const char *", "const char *", "const char *", "const char *")
int
pe__cluster_times_text(pcmk__output_t *out, va_list args) {
const char *last_written = va_arg(args, const char *);
const char *user = va_arg(args, const char *);
const char *client = va_arg(args, const char *);
const char *origin = va_arg(args, const char *);
char *buf = last_changed_string(last_written, user, client, origin);
out->list_item(out, "Last updated", "%s", pcmk__epoch2str(NULL));
out->list_item(out, "Last change", " %s", buf);
free(buf);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("failed-action", "xmlNodePtr")
int
pe__failed_action_text(pcmk__output_t *out, va_list args) {
xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
char *s = failed_action_string(xml_op);
out->list_item(out, NULL, "%s", s);
free(s);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("failed-action", "xmlNodePtr")
int
pe__failed_action_xml(pcmk__output_t *out, va_list args) {
xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
const char *last = crm_element_value(xml_op, XML_RSC_OP_LAST_CHANGE);
int rc = crm_parse_int(crm_element_value(xml_op, XML_LRM_ATTR_RC), "0");
int status = crm_parse_int(crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS), "0");
const char *exit_reason = crm_element_value(xml_op, XML_LRM_ATTR_EXIT_REASON);
char *rc_s = crm_itoa(rc);
char *reason_s = crm_xml_escape(exit_reason ? exit_reason : "none");
xmlNodePtr node = pcmk__output_create_xml_node(out, "failure",
op_key ? "op_key" : "id", op_key ? op_key : ID(xml_op),
"node", crm_element_value(xml_op, XML_ATTR_UNAME),
"exitstatus", services_ocf_exitcode_str(rc),
"exitreason", reason_s,
"exitcode", rc_s,
"call", crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
"status", services_lrm_status_str(status),
NULL);
if (last) {
guint interval_ms = 0;
char *s = NULL;
time_t when = crm_parse_int(last, "0");
crm_time_t *crm_when = crm_time_new(NULL);
char *rc_change = NULL;
crm_element_value_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
s = crm_itoa(interval_ms);
crm_time_set_timet(crm_when, &when);
rc_change = crm_time_as_string(crm_when, crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
pcmk__xe_set_props(node, XML_RSC_OP_LAST_CHANGE, rc_change,
"queued", crm_element_value(xml_op, XML_RSC_OP_T_QUEUE),
"exec", crm_element_value(xml_op, XML_RSC_OP_T_EXEC),
"interval", s,
"task", crm_element_value(xml_op, XML_LRM_ATTR_TASK),
NULL);
free(s);
free(rc_change);
crm_time_free(crm_when);
}
free(reason_s);
free(rc_s);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("node", "pe_node_t *", "unsigned int", "gboolean", "const char *",
- "gboolean", "gboolean", "gboolean", "GListPtr", "GListPtr")
+ "gboolean", "gboolean", "gboolean", "GList *", "GList *")
int
pe__node_html(pcmk__output_t *out, va_list args) {
pe_node_t *node = va_arg(args, pe_node_t *);
unsigned int print_opts = va_arg(args, unsigned int);
gboolean full = va_arg(args, gboolean);
const char *node_mode G_GNUC_UNUSED = va_arg(args, const char *);
gboolean print_clone_detail = va_arg(args, gboolean);
gboolean print_brief = va_arg(args, gboolean);
gboolean group_by_node = va_arg(args, gboolean);
- GListPtr only_node = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
char *node_name = pe__node_display_name(node, print_clone_detail);
char *buf = crm_strdup_printf("Node: %s", node_name);
if (full) {
xmlNodePtr item_node = pcmk__output_create_xml_node(out, "li", NULL);
pcmk_create_html_node(item_node, "span", NULL, NULL, buf);
if (node->details->standby_onfail && node->details->online) {
pcmk_create_html_node(item_node, "span", NULL, "standby", " standby (on-fail)");
} else if (node->details->standby && node->details->online) {
char *s = crm_strdup_printf(" standby%s", node->details->running_rsc ? " (with active resources)" : "");
pcmk_create_html_node(item_node, "span", NULL, " standby", s);
free(s);
} else if (node->details->standby) {
pcmk_create_html_node(item_node, "span", NULL, "offline", " OFFLINE (standby)");
} else if (node->details->maintenance && node->details->online) {
pcmk_create_html_node(item_node, "span", NULL, "maint", " maintenance");
} else if (node->details->maintenance) {
pcmk_create_html_node(item_node, "span", NULL, "offline", " OFFLINE (maintenance)");
} else if (node->details->online) {
pcmk_create_html_node(item_node, "span", NULL, "online", " online");
} else {
pcmk_create_html_node(item_node, "span", NULL, "offline", " OFFLINE");
}
if (print_brief && group_by_node) {
- GListPtr rscs = pe__filter_rsc_list(node->details->running_rsc, only_rsc);
+ GList *rscs = pe__filter_rsc_list(node->details->running_rsc, only_rsc);
if (rscs != NULL) {
out->begin_list(out, NULL, NULL, NULL);
pe__rscs_brief_output(out, rscs, print_opts | pe_print_rsconly, FALSE);
out->end_list(out);
}
} else if (group_by_node) {
- GListPtr lpc2 = NULL;
+ GList *lpc2 = NULL;
out->begin_list(out, NULL, NULL, NULL);
for (lpc2 = node->details->running_rsc; lpc2 != NULL; lpc2 = lpc2->next) {
pe_resource_t *rsc = (pe_resource_t *) lpc2->data;
out->message(out, crm_map_element_name(rsc->xml), print_opts | pe_print_rsconly,
rsc, only_node, only_rsc);
}
out->end_list(out);
}
} else {
out->begin_list(out, NULL, NULL, "%s", buf);
}
free(buf);
free(node_name);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("node", "pe_node_t *", "unsigned int", "gboolean", "const char *",
- "gboolean", "gboolean", "gboolean", "GListPtr", "GListPtr")
+ "gboolean", "gboolean", "gboolean", "GList *", "GList *")
int
pe__node_text(pcmk__output_t *out, va_list args) {
pe_node_t *node = va_arg(args, pe_node_t *);
unsigned int print_opts = va_arg(args, unsigned int);
gboolean full = va_arg(args, gboolean);
const char *node_mode = va_arg(args, const char *);
gboolean print_clone_detail = va_arg(args, gboolean);
gboolean print_brief = va_arg(args, gboolean);
gboolean group_by_node = va_arg(args, gboolean);
- GListPtr only_node = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
if (full) {
char *node_name = pe__node_display_name(node, print_clone_detail);
char *buf = NULL;
/* Print the node name and status */
if (pe__is_guest_node(node)) {
buf = crm_strdup_printf("GuestNode %s: %s", node_name, node_mode);
} else if (pe__is_remote_node(node)) {
buf = crm_strdup_printf("RemoteNode %s: %s", node_name, node_mode);
} else {
buf = crm_strdup_printf("Node %s: %s", node_name, node_mode);
}
/* If we're grouping by node, print its resources */
if (group_by_node) {
if (print_brief) {
- GListPtr rscs = pe__filter_rsc_list(node->details->running_rsc, only_rsc);
+ GList *rscs = pe__filter_rsc_list(node->details->running_rsc, only_rsc);
if (rscs != NULL) {
out->begin_list(out, NULL, NULL, "%s", buf);
out->begin_list(out, NULL, NULL, "Resources");
pe__rscs_brief_output(out, rscs, print_opts | pe_print_rsconly, FALSE);
out->end_list(out);
out->end_list(out);
}
} else {
- GListPtr gIter2 = NULL;
+ GList *gIter2 = NULL;
out->begin_list(out, NULL, NULL, "%s", buf);
out->begin_list(out, NULL, NULL, "Resources");
for (gIter2 = node->details->running_rsc; gIter2 != NULL; gIter2 = gIter2->next) {
pe_resource_t *rsc = (pe_resource_t *) gIter2->data;
out->message(out, crm_map_element_name(rsc->xml), print_opts | pe_print_rsconly,
rsc, only_node, only_rsc);
}
out->end_list(out);
out->end_list(out);
}
} else {
out->list_item(out, NULL, "%s", buf);
}
free(buf);
free(node_name);
} else {
out->begin_list(out, NULL, NULL, "Node: %s", pe__node_display_name(node, print_clone_detail));
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("node", "pe_node_t *", "unsigned int", "gboolean", "const char *",
- "gboolean", "gboolean", "gboolean", "GListPtr", "GListPtr")
+ "gboolean", "gboolean", "gboolean", "GList *", "GList *")
int
pe__node_xml(pcmk__output_t *out, va_list args) {
pe_node_t *node = va_arg(args, pe_node_t *);
unsigned int print_opts = va_arg(args, unsigned int);
gboolean full = va_arg(args, gboolean);
const char *node_mode G_GNUC_UNUSED = va_arg(args, const char *);
gboolean print_clone_detail G_GNUC_UNUSED = va_arg(args, gboolean);
gboolean print_brief G_GNUC_UNUSED = va_arg(args, gboolean);
gboolean group_by_node = va_arg(args, gboolean);
- GListPtr only_node = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
if (full) {
const char *node_type = "unknown";
char *length_s = crm_itoa(g_list_length(node->details->running_rsc));
switch (node->details->type) {
case node_member:
node_type = "member";
break;
case node_remote:
node_type = "remote";
break;
case node_ping:
node_type = "ping";
break;
}
pe__name_and_nvpairs_xml(out, true, "node", 13,
"name", node->details->uname,
"id", node->details->id,
"online", pcmk__btoa(node->details->online),
"standby", pcmk__btoa(node->details->standby),
"standby_onfail", pcmk__btoa(node->details->standby_onfail),
"maintenance", pcmk__btoa(node->details->maintenance),
"pending", pcmk__btoa(node->details->pending),
"unclean", pcmk__btoa(node->details->unclean),
"shutdown", pcmk__btoa(node->details->shutdown),
"expected_up", pcmk__btoa(node->details->expected_up),
"is_dc", pcmk__btoa(node->details->is_dc),
"resources_running", length_s,
"type", node_type);
if (pe__is_guest_node(node)) {
xmlNodePtr xml_node = pcmk__output_xml_peek_parent(out);
crm_xml_add(xml_node, "id_as_resource", node->details->remote_rsc->container->id);
}
if (group_by_node) {
- GListPtr lpc = NULL;
+ GList *lpc = NULL;
for (lpc = node->details->running_rsc; lpc != NULL; lpc = lpc->next) {
pe_resource_t *rsc = (pe_resource_t *) lpc->data;
out->message(out, crm_map_element_name(rsc->xml), print_opts | pe_print_rsconly,
rsc, only_node, only_rsc);
}
}
free(length_s);
out->end_list(out);
} else {
pcmk__output_xml_create_parent(out, "node",
"name", node->details->uname,
NULL);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "gboolean", "int")
int
pe__node_attribute_text(pcmk__output_t *out, va_list args) {
const char *name = va_arg(args, const char *);
const char *value = va_arg(args, const char *);
gboolean add_extra = va_arg(args, gboolean);
int expected_score = va_arg(args, int);
if (add_extra) {
int v = crm_parse_int(value, "0");
if (v <= 0) {
out->list_item(out, NULL, "%-32s\t: %-10s\t: Connectivity is lost", name, value);
} else if (v < expected_score) {
out->list_item(out, NULL, "%-32s\t: %-10s\t: Connectivity is degraded (Expected=%d)", name, value, expected_score);
} else {
out->list_item(out, NULL, "%-32s\t: %-10s", name, value);
}
} else {
out->list_item(out, NULL, "%-32s\t: %-10s", name, value);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "gboolean", "int")
int
pe__node_attribute_html(pcmk__output_t *out, va_list args) {
const char *name = va_arg(args, const char *);
const char *value = va_arg(args, const char *);
gboolean add_extra = va_arg(args, gboolean);
int expected_score = va_arg(args, int);
if (add_extra) {
int v = crm_parse_int(value, "0");
char *s = crm_strdup_printf("%s: %s", name, value);
xmlNodePtr item_node = pcmk__output_create_xml_node(out, "li", NULL);
pcmk_create_html_node(item_node, "span", NULL, NULL, s);
free(s);
if (v <= 0) {
pcmk_create_html_node(item_node, "span", NULL, "bold", "(connectivity is lost)");
} else if (v < expected_score) {
char *buf = crm_strdup_printf("(connectivity is degraded -- expected %d", expected_score);
pcmk_create_html_node(item_node, "span", NULL, "bold", buf);
free(buf);
}
} else {
out->list_item(out, NULL, "%s: %s", name, value);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("node-and-op", "pe_working_set_t *", "xmlNodePtr")
int
pe__node_and_op(pcmk__output_t *out, va_list args) {
pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
pe_resource_t *rsc = NULL;
gchar *node_str = NULL;
char *last_change_str = NULL;
const char *op_rsc = crm_element_value(xml_op, "resource");
const char *status_s = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS);
const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
int status = crm_parse_int(status_s, "0");
time_t last_change = 0;
rsc = pe_find_resource(data_set->resources, op_rsc);
if (rsc) {
pe_node_t *node = pe__current_node(rsc);
const char *target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
int opts = pe_print_rsconly | pe_print_pending;
if (node == NULL) {
node = rsc->pending_node;
}
node_str = pcmk__native_output_string(rsc, rsc_printable_id(rsc), node,
opts, target_role, false);
} else {
node_str = crm_strdup_printf("Unknown resource %s", op_rsc);
}
if (crm_element_value_epoch(xml_op, XML_RSC_OP_LAST_CHANGE,
&last_change) == pcmk_ok) {
last_change_str = crm_strdup_printf(", %s=%s, exec=%sms",
XML_RSC_OP_LAST_CHANGE,
crm_strip_trailing_newline(ctime(&last_change)),
crm_element_value(xml_op, XML_RSC_OP_T_EXEC));
}
out->list_item(out, NULL, "%s: %s (node=%s, call=%s, rc=%s%s): %s",
node_str, op_key ? op_key : ID(xml_op),
crm_element_value(xml_op, XML_ATTR_UNAME),
crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
crm_element_value(xml_op, XML_LRM_ATTR_RC),
last_change_str ? last_change_str : "",
services_lrm_status_str(status));
g_free(node_str);
free(last_change_str);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("node-and-op", "pe_working_set_t *", "xmlNodePtr")
int
pe__node_and_op_xml(pcmk__output_t *out, va_list args) {
pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
pe_resource_t *rsc = NULL;
const char *op_rsc = crm_element_value(xml_op, "resource");
const char *status_s = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS);
const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
int status = crm_parse_int(status_s, "0");
time_t last_change = 0;
xmlNode *node = pcmk__output_create_xml_node(out, "operation",
"op", op_key ? op_key : ID(xml_op),
"node", crm_element_value(xml_op, XML_ATTR_UNAME),
"call", crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
"rc", crm_element_value(xml_op, XML_LRM_ATTR_RC),
"status", services_lrm_status_str(status),
NULL);
rsc = pe_find_resource(data_set->resources, op_rsc);
if (rsc) {
const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
char *agent_tuple = NULL;
agent_tuple = crm_strdup_printf("%s:%s:%s", class,
pcmk_is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider) ? crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER) : "",
kind);
pcmk__xe_set_props(node, "rsc", rsc_printable_id(rsc),
"agent", agent_tuple,
NULL);
free(agent_tuple);
}
if (crm_element_value_epoch(xml_op, XML_RSC_OP_LAST_CHANGE,
&last_change) == pcmk_ok) {
pcmk__xe_set_props(node, XML_RSC_OP_LAST_CHANGE, crm_strip_trailing_newline(ctime(&last_change)),
XML_RSC_OP_T_EXEC, crm_element_value(xml_op, XML_RSC_OP_T_EXEC),
NULL);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "gboolean", "int")
int
pe__node_attribute_xml(pcmk__output_t *out, va_list args) {
const char *name = va_arg(args, const char *);
const char *value = va_arg(args, const char *);
gboolean add_extra = va_arg(args, gboolean);
int expected_score = va_arg(args, int);
xmlNodePtr node = pcmk__output_create_xml_node(out, "attribute",
"name", name,
"value", value,
NULL);
if (add_extra) {
char *buf = crm_itoa(expected_score);
crm_xml_add(node, "expected", buf);
free(buf);
}
return pcmk_rc_ok;
}
-PCMK__OUTPUT_ARGS("node-list", "GListPtr", "GListPtr", "GListPtr", "unsigned int", "gboolean", "gboolean", "gboolean")
+PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "unsigned int", "gboolean", "gboolean", "gboolean")
int
pe__node_list_html(pcmk__output_t *out, va_list args) {
- GListPtr nodes = va_arg(args, GListPtr);
- GListPtr only_node = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *nodes = va_arg(args, GList *);
+ GList *only_node = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
unsigned int print_opts = va_arg(args, unsigned int);
gboolean print_clone_detail = va_arg(args, gboolean);
gboolean print_brief = va_arg(args, gboolean);
gboolean group_by_node = va_arg(args, gboolean);
int rc = pcmk_rc_no_output;
- for (GListPtr gIter = nodes; gIter != NULL; gIter = gIter->next) {
+ for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
pe_node_t *node = (pe_node_t *) gIter->data;
if (!pcmk__str_in_list(only_node, node->details->uname)) {
continue;
}
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Node List");
out->message(out, "node", node, print_opts, TRUE, NULL, print_clone_detail,
print_brief, group_by_node, only_node, only_rsc);
}
PCMK__OUTPUT_LIST_FOOTER(out, rc);
return rc;
}
-PCMK__OUTPUT_ARGS("node-list", "GListPtr", "GListPtr", "GListPtr", "unsigned int", "gboolean", "gboolean", "gboolean")
+PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "unsigned int", "gboolean", "gboolean", "gboolean")
int
pe__node_list_text(pcmk__output_t *out, va_list args) {
- GListPtr nodes = va_arg(args, GListPtr);
- GListPtr only_node = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *nodes = va_arg(args, GList *);
+ GList *only_node = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
unsigned int print_opts = va_arg(args, unsigned int);
gboolean print_clone_detail = va_arg(args, gboolean);
gboolean print_brief = va_arg(args, gboolean);
gboolean group_by_node = va_arg(args, gboolean);
/* space-separated lists of node names */
char *online_nodes = NULL;
char *online_remote_nodes = NULL;
char *online_guest_nodes = NULL;
char *offline_nodes = NULL;
char *offline_remote_nodes = NULL;
size_t online_nodes_len = 0;
size_t online_remote_nodes_len = 0;
size_t online_guest_nodes_len = 0;
size_t offline_nodes_len = 0;
size_t offline_remote_nodes_len = 0;
int rc = pcmk_rc_no_output;
- for (GListPtr gIter = nodes; gIter != NULL; gIter = gIter->next) {
+ for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
pe_node_t *node = (pe_node_t *) gIter->data;
const char *node_mode = NULL;
char *node_name = pe__node_display_name(node, print_clone_detail);
if (!pcmk__str_in_list(only_node, node->details->uname)) {
free(node_name);
continue;
}
PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Node List");
/* Get node mode */
if (node->details->unclean) {
if (node->details->online) {
node_mode = "UNCLEAN (online)";
} else if (node->details->pending) {
node_mode = "UNCLEAN (pending)";
} else {
node_mode = "UNCLEAN (offline)";
}
} else if (node->details->pending) {
node_mode = "pending";
} else if (node->details->standby_onfail && node->details->online) {
node_mode = "standby (on-fail)";
} else if (node->details->standby) {
if (node->details->online) {
if (node->details->running_rsc) {
node_mode = "standby (with active resources)";
} else {
node_mode = "standby";
}
} else {
node_mode = "OFFLINE (standby)";
}
} else if (node->details->maintenance) {
if (node->details->online) {
node_mode = "maintenance";
} else {
node_mode = "OFFLINE (maintenance)";
}
} else if (node->details->online) {
node_mode = "online";
if (group_by_node == FALSE) {
if (pe__is_guest_node(node)) {
pcmk__add_word(&online_guest_nodes,
&online_guest_nodes_len, node_name);
} else if (pe__is_remote_node(node)) {
pcmk__add_word(&online_remote_nodes,
&online_remote_nodes_len, node_name);
} else {
pcmk__add_word(&online_nodes, &online_nodes_len, node_name);
}
free(node_name);
continue;
}
} else {
node_mode = "OFFLINE";
if (group_by_node == FALSE) {
if (pe__is_remote_node(node)) {
pcmk__add_word(&offline_remote_nodes,
&offline_remote_nodes_len, node_name);
} else if (pe__is_guest_node(node)) {
/* ignore offline guest nodes */
} else {
pcmk__add_word(&offline_nodes,
&offline_nodes_len, node_name);
}
free(node_name);
continue;
}
}
/* If we get here, node is in bad state, or we're grouping by node */
out->message(out, "node", node, print_opts, TRUE, node_mode, print_clone_detail,
print_brief, group_by_node, only_node, only_rsc);
free(node_name);
}
/* If we're not grouping by node, summarize nodes by status */
if (online_nodes) {
out->list_item(out, "Online", "[ %s ]", online_nodes);
free(online_nodes);
}
if (offline_nodes) {
out->list_item(out, "OFFLINE", "[ %s ]", offline_nodes);
free(offline_nodes);
}
if (online_remote_nodes) {
out->list_item(out, "RemoteOnline", "[ %s ]", online_remote_nodes);
free(online_remote_nodes);
}
if (offline_remote_nodes) {
out->list_item(out, "RemoteOFFLINE", "[ %s ]", offline_remote_nodes);
free(offline_remote_nodes);
}
if (online_guest_nodes) {
out->list_item(out, "GuestOnline", "[ %s ]", online_guest_nodes);
free(online_guest_nodes);
}
PCMK__OUTPUT_LIST_FOOTER(out, rc);
return rc;
}
-PCMK__OUTPUT_ARGS("node-list", "GListPtr", "GListPtr", "GListPtr", "unsigned int", "gboolean", "gboolean", "gboolean")
+PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "unsigned int", "gboolean", "gboolean", "gboolean")
int
pe__node_list_xml(pcmk__output_t *out, va_list args) {
- GListPtr nodes = va_arg(args, GListPtr);
- GListPtr only_node = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *nodes = va_arg(args, GList *);
+ GList *only_node = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
unsigned int print_opts = va_arg(args, unsigned int);
gboolean print_clone_detail = va_arg(args, gboolean);
gboolean print_brief = va_arg(args, gboolean);
gboolean group_by_node = va_arg(args, gboolean);
out->begin_list(out, NULL, NULL, "nodes");
- for (GListPtr gIter = nodes; gIter != NULL; gIter = gIter->next) {
+ for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
pe_node_t *node = (pe_node_t *) gIter->data;
if (!pcmk__str_in_list(only_node, node->details->uname)) {
continue;
}
out->message(out, "node", node, print_opts, TRUE, NULL, print_clone_detail,
print_brief, group_by_node, only_node, only_rsc);
}
out->end_list(out);
return pcmk_rc_ok;
}
-PCMK__OUTPUT_ARGS("op-history", "struct xmlNode *", "const char *", "const char *", "int", "gboolean")
+PCMK__OUTPUT_ARGS("op-history", "xmlNodePtr", "const char *", "const char *", "int", "gboolean")
int
pe__op_history_text(pcmk__output_t *out, va_list args) {
- xmlNode *xml_op = va_arg(args, xmlNode *);
+ xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
const char *task = va_arg(args, const char *);
const char *interval_ms_s = va_arg(args, const char *);
int rc = va_arg(args, int);
gboolean print_timing = va_arg(args, gboolean);
char *buf = op_history_string(xml_op, task, interval_ms_s, rc, print_timing);
out->list_item(out, NULL, "%s", buf);
free(buf);
return pcmk_rc_ok;
}
-PCMK__OUTPUT_ARGS("op-history", "struct xmlNode *", "const char *", "const char *", "int", "gboolean")
+PCMK__OUTPUT_ARGS("op-history", "xmlNodePtr", "const char *", "const char *", "int", "gboolean")
int
pe__op_history_xml(pcmk__output_t *out, va_list args) {
- xmlNode *xml_op = va_arg(args, xmlNode *);
+ xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
const char *task = va_arg(args, const char *);
const char *interval_ms_s = va_arg(args, const char *);
int rc = va_arg(args, int);
gboolean print_timing = va_arg(args, gboolean);
char *rc_s = crm_itoa(rc);
xmlNodePtr node = pcmk__output_create_xml_node(out, "operation_history",
"call", crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
"task", task,
"rc", rc_s,
"rc_text", services_ocf_exitcode_str(rc),
NULL);
free(rc_s);
if (interval_ms_s && !pcmk__str_eq(interval_ms_s, "0", pcmk__str_casei)) {
char *s = crm_strdup_printf("%sms", interval_ms_s);
crm_xml_add(node, "interval", s);
free(s);
}
if (print_timing) {
const char *value = NULL;
value = crm_element_value(xml_op, XML_RSC_OP_LAST_CHANGE);
if (value) {
time_t int_value = (time_t) crm_parse_int(value, NULL);
if (int_value > 0) {
crm_xml_add(node, XML_RSC_OP_LAST_CHANGE, pcmk__epoch2str(&int_value));
}
}
value = crm_element_value(xml_op, XML_RSC_OP_LAST_RUN);
if (value) {
time_t int_value = (time_t) crm_parse_int(value, NULL);
if (int_value > 0) {
crm_xml_add(node, XML_RSC_OP_LAST_RUN, pcmk__epoch2str(&int_value));
}
}
value = crm_element_value(xml_op, XML_RSC_OP_T_EXEC);
if (value) {
char *s = crm_strdup_printf("%sms", value);
crm_xml_add(node, XML_RSC_OP_T_EXEC, s);
free(s);
}
value = crm_element_value(xml_op, XML_RSC_OP_T_QUEUE);
if (value) {
char *s = crm_strdup_printf("%sms", value);
crm_xml_add(node, XML_RSC_OP_T_QUEUE, s);
free(s);
}
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("resource-config", "pe_resource_t *", "gboolean")
int pe__resource_config(pcmk__output_t *out, va_list args) {
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
gboolean raw = va_arg(args, gboolean);
char *rsc_xml = NULL;
if (raw) {
rsc_xml = dump_xml_formatted(rsc->orig_xml ? rsc->orig_xml : rsc->xml);
} else {
rsc_xml = dump_xml_formatted(rsc->xml);
}
out->info(out, "Resource XML:");
out->output_xml(out, "xml", rsc_xml);
free(rsc_xml);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("resource-history", "pe_resource_t *", "const char *", "gboolean", "int", "time_t", "gboolean")
int
pe__resource_history_text(pcmk__output_t *out, va_list args) {
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
const char *rsc_id = va_arg(args, const char *);
gboolean all = va_arg(args, gboolean);
int failcount = va_arg(args, int);
time_t last_failure = va_arg(args, int);
gboolean as_header = va_arg(args, gboolean);
char *buf = resource_history_string(rsc, rsc_id, all, failcount, last_failure);
if (as_header) {
out->begin_list(out, NULL, NULL, "%s", buf);
} else {
out->list_item(out, NULL, "%s", buf);
}
free(buf);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("resource-history", "pe_resource_t *", "const char *", "gboolean", "int", "time_t", "gboolean")
int
pe__resource_history_xml(pcmk__output_t *out, va_list args) {
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
const char *rsc_id = va_arg(args, const char *);
gboolean all = va_arg(args, gboolean);
int failcount = va_arg(args, int);
time_t last_failure = va_arg(args, int);
gboolean as_header = va_arg(args, gboolean);
xmlNodePtr node = pcmk__output_xml_create_parent(out, "resource_history",
"id", rsc_id,
NULL);
if (rsc == NULL) {
crm_xml_add(node, "orphan", "true");
} else if (all || failcount || last_failure > 0) {
char *migration_s = crm_itoa(rsc->migration_threshold);
pcmk__xe_set_props(node, "orphan", "false",
"migration-threshold", migration_s,
NULL);
free(migration_s);
if (failcount > 0) {
char *s = crm_itoa(failcount);
crm_xml_add(node, PCMK__FAIL_COUNT_PREFIX, s);
free(s);
}
if (last_failure > 0) {
crm_xml_add(node, PCMK__LAST_FAILURE_PREFIX, pcmk__epoch2str(&last_failure));
}
}
if (as_header == FALSE) {
pcmk__output_xml_pop_parent(out);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("resource-list", "pe_working_set_t *", "unsigned int", "gboolean",
- "gboolean", "gboolean", "gboolean", "GListPtr", "GListPtr", "gboolean")
+ "gboolean", "gboolean", "gboolean", "GList *", "GList *", "gboolean")
int
pe__resource_list(pcmk__output_t *out, va_list args)
{
pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
unsigned int print_opts = va_arg(args, unsigned int);
gboolean group_by_node = va_arg(args, gboolean);
gboolean inactive_resources = va_arg(args, gboolean);
gboolean brief_output = va_arg(args, gboolean);
gboolean print_summary = va_arg(args, gboolean);
- GListPtr only_node = va_arg(args, GListPtr);
- GListPtr only_rsc = va_arg(args, GListPtr);
+ GList *only_node = va_arg(args, GList *);
+ GList *only_rsc = va_arg(args, GList *);
gboolean print_spacer = va_arg(args, gboolean);
- GListPtr rsc_iter;
+ GList *rsc_iter;
int rc = pcmk_rc_no_output;
/* If we already showed active resources by node, and
* we're not showing inactive resources, we have nothing to do
*/
if (group_by_node && !inactive_resources) {
return rc;
}
PCMK__OUTPUT_SPACER_IF(out, print_spacer);
if (group_by_node) {
/* Active resources have already been printed by node */
out->begin_list(out, NULL, NULL, "Inactive Resources");
} else if (inactive_resources) {
out->begin_list(out, NULL, NULL, "Full List of Resources");
} else {
out->begin_list(out, NULL, NULL, "Active Resources");
}
/* If we haven't already printed resources grouped by node,
* and brief output was requested, print resource summary */
if (brief_output && !group_by_node) {
- GListPtr rscs = pe__filter_rsc_list(data_set->resources, only_rsc);
+ GList *rscs = pe__filter_rsc_list(data_set->resources, only_rsc);
pe__rscs_brief_output(out, rscs, print_opts, inactive_resources);
g_list_free(rscs);
}
/* For each resource, display it if appropriate */
for (rsc_iter = data_set->resources; rsc_iter != NULL; rsc_iter = rsc_iter->next) {
pe_resource_t *rsc = (pe_resource_t *) rsc_iter->data;
int x;
/* Complex resources may have some sub-resources active and some inactive */
gboolean is_active = rsc->fns->active(rsc, TRUE);
gboolean partially_active = rsc->fns->active(rsc, FALSE);
/* Skip inactive orphans (deleted but still in CIB) */
if (pcmk_is_set(rsc->flags, pe_rsc_orphan) && !is_active) {
continue;
/* Skip active resources if we already displayed them by node */
} else if (group_by_node) {
if (is_active) {
continue;
}
/* Skip primitives already counted in a brief summary */
} else if (brief_output && (rsc->variant == pe_native)) {
continue;
/* Skip resources that aren't at least partially active,
* unless we're displaying inactive resources
*/
} else if (!partially_active && !inactive_resources) {
continue;
} else if (partially_active && !pe__rsc_running_on_any_node_in_list(rsc, only_node)) {
continue;
}
/* Print this resource */
x = out->message(out, crm_map_element_name(rsc->xml), print_opts, rsc,
only_node, only_rsc);
if (x == pcmk_rc_ok) {
rc = pcmk_rc_ok;
}
}
if (print_summary && rc != pcmk_rc_ok) {
if (group_by_node) {
out->list_item(out, NULL, "No inactive resources");
} else if (inactive_resources) {
out->list_item(out, NULL, "No resources");
} else {
out->list_item(out, NULL, "No active resources");
}
}
out->end_list(out);
return rc;
}
PCMK__OUTPUT_ARGS("ticket", "pe_ticket_t *")
int
pe__ticket_html(pcmk__output_t *out, va_list args) {
pe_ticket_t *ticket = va_arg(args, pe_ticket_t *);
if (ticket->last_granted > -1) {
char *time = pcmk_format_named_time("last-granted", ticket->last_granted);
out->list_item(out, NULL, "%s:\t%s%s %s", ticket->id,
ticket->granted ? "granted" : "revoked",
ticket->standby ? " [standby]" : "",
time);
free(time);
} else {
out->list_item(out, NULL, "%s:\t%s%s", ticket->id,
ticket->granted ? "granted" : "revoked",
ticket->standby ? " [standby]" : "");
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("ticket", "pe_ticket_t *")
int
pe__ticket_text(pcmk__output_t *out, va_list args) {
pe_ticket_t *ticket = va_arg(args, pe_ticket_t *);
if (ticket->last_granted > -1) {
char *time = pcmk_format_named_time("last-granted", ticket->last_granted);
out->list_item(out, ticket->id, "\t%s%s %s",
ticket->granted ? "granted" : "revoked",
ticket->standby ? " [standby]" : "",
time);
free(time);
} else {
out->list_item(out, ticket->id, "\t%s%s",
ticket->granted ? "granted" : "revoked",
ticket->standby ? " [standby]" : "");
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("ticket", "pe_ticket_t *")
int
pe__ticket_xml(pcmk__output_t *out, va_list args) {
xmlNodePtr node = NULL;
pe_ticket_t *ticket = va_arg(args, pe_ticket_t *);
node = pcmk__output_create_xml_node(out, "ticket",
"id", ticket->id,
"status", ticket->granted ? "granted" : "revoked",
"standby", pcmk__btoa(ticket->standby),
NULL);
if (ticket->last_granted > -1) {
crm_xml_add(node, "last-granted", pcmk__epoch2str(&ticket->last_granted));
}
return pcmk_rc_ok;
}
static pcmk__message_entry_t fmt_functions[] = {
{ "ban", "html", pe__ban_html },
{ "ban", "log", pe__ban_text },
{ "ban", "text", pe__ban_text },
{ "ban", "xml", pe__ban_xml },
{ "bundle", "xml", pe__bundle_xml },
{ "bundle", "html", pe__bundle_html },
{ "bundle", "text", pe__bundle_text },
{ "bundle", "log", pe__bundle_text },
{ "clone", "xml", pe__clone_xml },
{ "clone", "html", pe__clone_html },
{ "clone", "text", pe__clone_text },
{ "clone", "log", pe__clone_text },
{ "cluster-counts", "html", pe__cluster_counts_html },
{ "cluster-counts", "log", pe__cluster_counts_text },
{ "cluster-counts", "text", pe__cluster_counts_text },
{ "cluster-counts", "xml", pe__cluster_counts_xml },
{ "cluster-dc", "html", pe__cluster_dc_html },
{ "cluster-dc", "log", pe__cluster_dc_text },
{ "cluster-dc", "text", pe__cluster_dc_text },
{ "cluster-dc", "xml", pe__cluster_dc_xml },
{ "cluster-options", "html", pe__cluster_options_html },
{ "cluster-options", "log", pe__cluster_options_log },
{ "cluster-options", "text", pe__cluster_options_text },
{ "cluster-options", "xml", pe__cluster_options_xml },
{ "cluster-summary", "default", pe__cluster_summary },
{ "cluster-summary", "html", pe__cluster_summary_html },
{ "cluster-stack", "html", pe__cluster_stack_html },
{ "cluster-stack", "log", pe__cluster_stack_text },
{ "cluster-stack", "text", pe__cluster_stack_text },
{ "cluster-stack", "xml", pe__cluster_stack_xml },
{ "cluster-times", "html", pe__cluster_times_html },
{ "cluster-times", "log", pe__cluster_times_text },
{ "cluster-times", "text", pe__cluster_times_text },
{ "cluster-times", "xml", pe__cluster_times_xml },
{ "failed-action", "default", pe__failed_action_text },
{ "failed-action", "xml", pe__failed_action_xml },
{ "group", "xml", pe__group_xml },
{ "group", "html", pe__group_html },
{ "group", "text", pe__group_text },
{ "group", "log", pe__group_text },
{ "maint-mode", "text", pe__cluster_maint_mode_text },
{ "node", "html", pe__node_html },
{ "node", "log", pe__node_text },
{ "node", "text", pe__node_text },
{ "node", "xml", pe__node_xml },
{ "node-and-op", "default", pe__node_and_op },
{ "node-and-op", "xml", pe__node_and_op_xml },
{ "node-list", "html", pe__node_list_html },
{ "node-list", "log", pe__node_list_text },
{ "node-list", "text", pe__node_list_text },
{ "node-list", "xml", pe__node_list_xml },
{ "node-attribute", "html", pe__node_attribute_html },
{ "node-attribute", "log", pe__node_attribute_text },
{ "node-attribute", "text", pe__node_attribute_text },
{ "node-attribute", "xml", pe__node_attribute_xml },
{ "op-history", "default", pe__op_history_text },
{ "op-history", "xml", pe__op_history_xml },
{ "primitive", "xml", pe__resource_xml },
{ "primitive", "html", pe__resource_html },
{ "primitive", "text", pe__resource_text },
{ "primitive", "log", pe__resource_text },
{ "resource-config", "default", pe__resource_config },
{ "resource-history", "default", pe__resource_history_text },
{ "resource-history", "xml", pe__resource_history_xml },
{ "resource-list", "default", pe__resource_list },
{ "ticket", "html", pe__ticket_html },
{ "ticket", "log", pe__ticket_text },
{ "ticket", "text", pe__ticket_text },
{ "ticket", "xml", pe__ticket_xml },
{ NULL, NULL, NULL }
};
void
pe__register_messages(pcmk__output_t *out) {
pcmk__register_messages(out, fmt_functions);
}
void
pe__output_node(pe_node_t *node, gboolean details, pcmk__output_t *out)
{
if (node == NULL) {
crm_trace("<NULL>");
return;
}
CRM_ASSERT(node->details);
crm_trace("%sNode %s: (weight=%d, fixed=%s)",
node->details->online ? "" : "Unavailable/Unclean ",
node->details->uname, node->weight, node->fixed ? "True" : "False");
if (details) {
char *pe_mutable = strdup("\t\t");
GListPtr gIter = node->details->running_rsc;
GListPtr all = NULL;
all = g_list_prepend(all, strdup("*"));
crm_trace("\t\t===Node Attributes");
g_hash_table_foreach(node->details->attrs, print_str_str, pe_mutable);
free(pe_mutable);
crm_trace("\t\t=== Resources");
for (; gIter != NULL; gIter = gIter->next) {
pe_resource_t *rsc = (pe_resource_t *) gIter->data;
out->message(out, crm_map_element_name(rsc->xml),
pe_print_pending, rsc, all, all);
}
g_list_free_full(all, free);
}
}
diff --git a/tools/crm_resource_print.c b/tools/crm_resource_print.c
index cb0687903f..4cb78b53d9 100644
--- a/tools/crm_resource_print.c
+++ b/tools/crm_resource_print.c
@@ -1,575 +1,575 @@
/*
* Copyright 2004-2020 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_resource.h>
#include <crm/common/lists_internal.h>
#include <crm/common/xml_internal.h>
#include <crm/common/output_internal.h>
#define cons_string(x) x?x:"NA"
void
cli_resource_print_cts_constraints(pcmk__output_t *out, pe_working_set_t * data_set)
{
xmlNode *xml_obj = NULL;
xmlNode *lifetime = NULL;
xmlNode *cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, data_set->input);
for (xml_obj = pcmk__xe_first_child(cib_constraints); xml_obj != NULL;
xml_obj = pcmk__xe_next(xml_obj)) {
const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
if (id == NULL) {
continue;
}
// @COMPAT lifetime is deprecated
lifetime = first_named_child(xml_obj, "lifetime");
if (pe_evaluate_rules(lifetime, NULL, data_set->now, NULL) == FALSE) {
continue;
}
if (!pcmk__str_eq(XML_CONS_TAG_RSC_DEPEND, crm_element_name(xml_obj), pcmk__str_casei)) {
continue;
}
out->info(out, "Constraint %s %s %s %s %s %s %s",
crm_element_name(xml_obj),
cons_string(crm_element_value(xml_obj, XML_ATTR_ID)),
cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE)),
cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET)),
cons_string(crm_element_value(xml_obj, XML_RULE_ATTR_SCORE)),
cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_ROLE)),
cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET_ROLE)));
}
}
void
cli_resource_print_cts(pcmk__output_t *out, pe_resource_t * rsc)
{
GListPtr lpc = NULL;
const char *host = NULL;
bool needs_quorum = TRUE;
const char *rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE);
const char *rprov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
const char *rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
pe_node_t *node = pe__current_node(rsc);
if (pcmk__str_eq(rclass, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
needs_quorum = FALSE;
} else {
// @TODO check requires in resource meta-data and rsc_defaults
}
if (node != NULL) {
host = node->details->uname;
}
out->info(out, "Resource: %s %s %s %s %s %s %s %s %d %lld 0x%.16llx",
crm_element_name(rsc->xml), rsc->id,
rsc->clone_name ? rsc->clone_name : rsc->id, rsc->parent ? rsc->parent->id : "NA",
rprov ? rprov : "NA", rclass, rtype, host ? host : "NA", needs_quorum, rsc->flags,
rsc->flags);
for (lpc = rsc->children; lpc != NULL; lpc = lpc->next) {
pe_resource_t *child = (pe_resource_t *) lpc->data;
cli_resource_print_cts(out, child);
}
}
// \return Standard Pacemaker return code
int
cli_resource_print_operations(pcmk__output_t *out, const char *rsc_id,
const char *host_uname, bool active,
pe_working_set_t * data_set)
{
int rc = pcmk_rc_no_output;
GListPtr ops = find_operations(rsc_id, host_uname, active, data_set);
if (!ops) {
return rc;
}
out->begin_list(out, NULL, NULL, "Resource Operations");
rc = pcmk_rc_ok;
for (GListPtr lpc = ops; lpc != NULL; lpc = lpc->next) {
xmlNode *xml_op = (xmlNode *) lpc->data;
out->message(out, "node-and-op", data_set, xml_op);
}
out->end_list(out);
return rc;
}
// \return Standard Pacemaker return code
int
cli_resource_print(pcmk__output_t *out, pe_resource_t *rsc,
pe_working_set_t *data_set, bool expanded)
{
unsigned int opts = pe_print_pending;
GListPtr all = NULL;
all = g_list_prepend(all, strdup("*"));
out->begin_list(out, NULL, NULL, "Resource Config");
out->message(out, crm_map_element_name(rsc->xml), opts, rsc, all, all);
out->message(out, "resource-config", rsc, !expanded);
out->end_list(out);
g_list_free_full(all, free);
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("attribute", "pe_resource_t *", "char *", "GHashTable *")
static int
attribute_default(pcmk__output_t *out, va_list args) {
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
char *attr = va_arg(args, char *);
GHashTable *params = va_arg(args, GHashTable *);
const char *value = g_hash_table_lookup(params, attr);
if (value != NULL) {
out->begin_list(out, NULL, NULL, "Attributes");
out->list_item(out, attr, "%s", value);
out->end_list(out);
} else {
out->err(out, "Attribute '%s' not found for '%s'", attr, rsc->id);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("attribute", "pe_resource_t *", "char *", "GHashTable *")
static int
attribute_text(pcmk__output_t *out, va_list args) {
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
char *attr = va_arg(args, char *);
GHashTable *params = va_arg(args, GHashTable *);
const char *value = g_hash_table_lookup(params, attr);
if (value != NULL) {
out->info(out, "%s", value);
} else {
out->err(out, "Attribute '%s' not found for '%s'", attr, rsc->id);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("property", "pe_resource_t *", "char *")
static int
property_default(pcmk__output_t *out, va_list args) {
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
char *attr = va_arg(args, char *);
const char *value = crm_element_value(rsc->xml, attr);
if (value != NULL) {
out->begin_list(out, NULL, NULL, "Properties");
out->list_item(out, attr, "%s", value);
out->end_list(out);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("property", "pe_resource_t *", "char *")
static int
property_text(pcmk__output_t *out, va_list args) {
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
char *attr = va_arg(args, char *);
const char *value = crm_element_value(rsc->xml, attr);
if (value != NULL) {
out->info(out, "%s", value);
}
return pcmk_rc_ok;
}
PCMK__OUTPUT_ARGS("resource-check", "resource_checks_t *")
static int
resource_check_default(pcmk__output_t *out, va_list args) {
resource_checks_t *checks = va_arg(args, resource_checks_t *);
pe_resource_t *parent = uber_parent(checks->rsc);
int rc = pcmk_rc_no_output;
bool printed = false;
if (checks->flags != 0 || checks->lock_node != NULL) {
printed = true;
out->begin_list(out, NULL, NULL, "Resource Checks");
}
if (pcmk_is_set(checks->flags, rsc_remain_stopped)) {
out->list_item(out, "check", "Configuration specifies '%s' should remain stopped",
parent->id);
}
if (pcmk_is_set(checks->flags, rsc_unpromotable)) {
out->list_item(out, "check", "Configuration specifies '%s' should not be promoted",
parent->id);
}
if (pcmk_is_set(checks->flags, rsc_unmanaged)) {
out->list_item(out, "check", "Configuration prevents cluster from stopping or starting unmanaged '%s'",
parent->id);
}
if (checks->lock_node) {
out->list_item(out, "check", "'%s' is locked to node %s due to shutdown",
parent->id, checks->lock_node);
}
if (printed) {
out->end_list(out);
rc = pcmk_rc_ok;
}
return rc;
}
PCMK__OUTPUT_ARGS("resource-check", "resource_checks_t *")
static int
resource_check_xml(pcmk__output_t *out, va_list args) {
resource_checks_t *checks = va_arg(args, resource_checks_t *);
pe_resource_t *parent = uber_parent(checks->rsc);
int rc = pcmk_rc_no_output;
- xmlNode *node = pcmk__output_create_xml_node(out, "check",
- "id", parent->id,
- NULL);
+ xmlNodePtr node = pcmk__output_create_xml_node(out, "check",
+ "id", parent->id,
+ NULL);
if (pcmk_is_set(checks->flags, rsc_remain_stopped)) {
crm_xml_add(node, "remain_stopped", "true");
}
if (pcmk_is_set(checks->flags, rsc_unpromotable)) {
crm_xml_add(node, "promotable", "false");
}
if (pcmk_is_set(checks->flags, rsc_unmanaged)) {
crm_xml_add(node, "unmanaged", "true");
}
if (checks->lock_node) {
crm_xml_add(node, "locked-to", checks->lock_node);
}
return rc;
}
-PCMK__OUTPUT_ARGS("resource-search", "GListPtr", "pe_resource_t *", "gchar *")
+PCMK__OUTPUT_ARGS("resource-search", "GList *", "pe_resource_t *", "gchar *")
static int
resource_search_default(pcmk__output_t *out, va_list args)
{
- GListPtr nodes = va_arg(args, GListPtr);
+ GList *nodes = va_arg(args, GList *);
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
gchar *requested_name = va_arg(args, gchar *);
bool printed = false;
int rc = pcmk_rc_no_output;
if (!out->is_quiet(out) && nodes == NULL) {
out->err(out, "resource %s is NOT running", requested_name);
return rc;
}
- for (GListPtr lpc = nodes; lpc != NULL; lpc = lpc->next) {
+ for (GList *lpc = nodes; lpc != NULL; lpc = lpc->next) {
pe_node_t *node = (pe_node_t *) lpc->data;
if (!printed) {
out->begin_list(out, NULL, NULL, "Nodes");
printed = true;
rc = pcmk_rc_ok;
}
if (out->is_quiet(out)) {
out->list_item(out, "node", "%s", node->details->uname);
} else {
const char *state = "";
if (!pe_rsc_is_clone(rsc) && rsc->fns->state(rsc, TRUE) == RSC_ROLE_MASTER) {
state = " Master";
}
out->list_item(out, "node", "resource %s is running on: %s%s",
requested_name, node->details->uname, state);
}
}
if (printed) {
out->end_list(out);
}
return rc;
}
-PCMK__OUTPUT_ARGS("resource-search", "GListPtr", "pe_resource_t *", "gchar *")
+PCMK__OUTPUT_ARGS("resource-search", "GList *", "pe_resource_t *", "gchar *")
static int
resource_search_xml(pcmk__output_t *out, va_list args)
{
- GListPtr nodes = va_arg(args, GListPtr);
+ GList *nodes = va_arg(args, GList *);
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
gchar *requested_name = va_arg(args, gchar *);
pcmk__output_xml_create_parent(out, "nodes",
"resource", requested_name,
NULL);
- for (GListPtr lpc = nodes; lpc != NULL; lpc = lpc->next) {
+ for (GList *lpc = nodes; lpc != NULL; lpc = lpc->next) {
pe_node_t *node = (pe_node_t *) lpc->data;
- xmlNode *sub_node = pcmk__output_create_xml_text_node(out, "node", node->details->uname);
+ xmlNodePtr sub_node = pcmk__output_create_xml_text_node(out, "node", node->details->uname);
if (!pe_rsc_is_clone(rsc) && rsc->fns->state(rsc, TRUE) == RSC_ROLE_MASTER) {
crm_xml_add(sub_node, "state", "promoted");
}
}
return pcmk_rc_ok;
}
-PCMK__OUTPUT_ARGS("resource-why", "cib_t *", "GListPtr", "pe_resource_t *",
+PCMK__OUTPUT_ARGS("resource-why", "cib_t *", "GList *", "pe_resource_t *",
"pe_node_t *")
static int
resource_why_default(pcmk__output_t *out, va_list args)
{
cib_t *cib_conn = va_arg(args, cib_t *);
- GListPtr resources = va_arg(args, GListPtr);
+ GList *resources = va_arg(args, GList *);
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
pe_node_t *node = va_arg(args, pe_node_t *);
const char *host_uname = (node == NULL)? NULL : node->details->uname;
out->begin_list(out, NULL, NULL, "Resource Reasons");
if ((rsc == NULL) && (host_uname == NULL)) {
- GListPtr lpc = NULL;
- GListPtr hosts = NULL;
+ GList *lpc = NULL;
+ GList *hosts = NULL;
for (lpc = resources; lpc != NULL; lpc = lpc->next) {
pe_resource_t *rsc = (pe_resource_t *) lpc->data;
rsc->fns->location(rsc, &hosts, TRUE);
if (hosts == NULL) {
out->list_item(out, "reason", "Resource %s is not running", rsc->id);
} else {
out->list_item(out, "reason", "Resource %s is running", rsc->id);
}
cli_resource_check(out, cib_conn, rsc);
g_list_free(hosts);
hosts = NULL;
}
} else if ((rsc != NULL) && (host_uname != NULL)) {
if (resource_is_running_on(rsc, host_uname)) {
out->list_item(out, "reason", "Resource %s is running on host %s",
rsc->id, host_uname);
} else {
out->list_item(out, "reason", "Resource %s is not running on host %s",
rsc->id, host_uname);
}
cli_resource_check(out, cib_conn, rsc);
} else if ((rsc == NULL) && (host_uname != NULL)) {
const char* host_uname = node->details->uname;
- GListPtr allResources = node->details->allocated_rsc;
- GListPtr activeResources = node->details->running_rsc;
- GListPtr unactiveResources = pcmk__subtract_lists(allResources, activeResources, (GCompareFunc) strcmp);
- GListPtr lpc = NULL;
+ GList *allResources = node->details->allocated_rsc;
+ GList *activeResources = node->details->running_rsc;
+ GList *unactiveResources = pcmk__subtract_lists(allResources, activeResources, (GCompareFunc) strcmp);
+ GList *lpc = NULL;
for (lpc = activeResources; lpc != NULL; lpc = lpc->next) {
pe_resource_t *rsc = (pe_resource_t *) lpc->data;
out->list_item(out, "reason", "Resource %s is running on host %s",
rsc->id, host_uname);
cli_resource_check(out, cib_conn, rsc);
}
for(lpc = unactiveResources; lpc != NULL; lpc = lpc->next) {
pe_resource_t *rsc = (pe_resource_t *) lpc->data;
out->list_item(out, "reason", "Resource %s is assigned to host %s but not running",
rsc->id, host_uname);
cli_resource_check(out, cib_conn, rsc);
}
g_list_free(allResources);
g_list_free(activeResources);
g_list_free(unactiveResources);
} else if ((rsc != NULL) && (host_uname == NULL)) {
- GListPtr hosts = NULL;
+ GList *hosts = NULL;
rsc->fns->location(rsc, &hosts, TRUE);
out->list_item(out, "reason", "Resource %s is %srunning",
rsc->id, (hosts? "" : "not "));
cli_resource_check(out, cib_conn, rsc);
g_list_free(hosts);
}
out->end_list(out);
return pcmk_rc_ok;
}
-PCMK__OUTPUT_ARGS("resource-why", "cib_t *", "GListPtr", "pe_resource_t *",
+PCMK__OUTPUT_ARGS("resource-why", "cib_t *", "GList *", "pe_resource_t *",
"pe_node_t *")
static int
resource_why_xml(pcmk__output_t *out, va_list args)
{
cib_t *cib_conn = va_arg(args, cib_t *);
- GListPtr resources = va_arg(args, GListPtr);
+ GList *resources = va_arg(args, GList *);
pe_resource_t *rsc = va_arg(args, pe_resource_t *);
pe_node_t *node = va_arg(args, pe_node_t *);
const char *host_uname = (node == NULL)? NULL : node->details->uname;
- xmlNode *xml_node = pcmk__output_xml_create_parent(out, "reason", NULL);
+ xmlNodePtr xml_node = pcmk__output_xml_create_parent(out, "reason", NULL);
if ((rsc == NULL) && (host_uname == NULL)) {
- GListPtr lpc = NULL;
- GListPtr hosts = NULL;
+ GList *lpc = NULL;
+ GList *hosts = NULL;
pcmk__output_xml_create_parent(out, "resources", NULL);
for (lpc = resources; lpc != NULL; lpc = lpc->next) {
pe_resource_t *rsc = (pe_resource_t *) lpc->data;
rsc->fns->location(rsc, &hosts, TRUE);
pcmk__output_xml_create_parent(out, "resource",
"id", rsc->id,
"running", pcmk__btoa(hosts != NULL),
NULL);
cli_resource_check(out, cib_conn, rsc);
pcmk__output_xml_pop_parent(out);
g_list_free(hosts);
hosts = NULL;
}
pcmk__output_xml_pop_parent(out);
} else if ((rsc != NULL) && (host_uname != NULL)) {
if (resource_is_running_on(rsc, host_uname)) {
crm_xml_add(xml_node, "running_on", host_uname);
}
cli_resource_check(out, cib_conn, rsc);
} else if ((rsc == NULL) && (host_uname != NULL)) {
const char* host_uname = node->details->uname;
- GListPtr allResources = node->details->allocated_rsc;
- GListPtr activeResources = node->details->running_rsc;
- GListPtr unactiveResources = pcmk__subtract_lists(allResources, activeResources, (GCompareFunc) strcmp);
- GListPtr lpc = NULL;
+ GList *allResources = node->details->allocated_rsc;
+ GList *activeResources = node->details->running_rsc;
+ GList *unactiveResources = pcmk__subtract_lists(allResources, activeResources, (GCompareFunc) strcmp);
+ GList *lpc = NULL;
pcmk__output_xml_create_parent(out, "resources", NULL);
for (lpc = activeResources; lpc != NULL; lpc = lpc->next) {
pe_resource_t *rsc = (pe_resource_t *) lpc->data;
pcmk__output_xml_create_parent(out, "resource",
"id", rsc->id,
"running", "true",
"host", host_uname,
NULL);
cli_resource_check(out, cib_conn, rsc);
pcmk__output_xml_pop_parent(out);
}
for(lpc = unactiveResources; lpc != NULL; lpc = lpc->next) {
pe_resource_t *rsc = (pe_resource_t *) lpc->data;
pcmk__output_xml_create_parent(out, "resource",
"id", rsc->id,
"running", "false",
"host", host_uname,
NULL);
cli_resource_check(out, cib_conn, rsc);
pcmk__output_xml_pop_parent(out);
}
pcmk__output_xml_pop_parent(out);
g_list_free(allResources);
g_list_free(activeResources);
g_list_free(unactiveResources);
} else if ((rsc != NULL) && (host_uname == NULL)) {
- GListPtr hosts = NULL;
+ GList *hosts = NULL;
rsc->fns->location(rsc, &hosts, TRUE);
crm_xml_add(xml_node, "running", pcmk__btoa(hosts != NULL));
cli_resource_check(out, cib_conn, rsc);
g_list_free(hosts);
}
return pcmk_rc_ok;
}
static void
add_resource_name(pcmk__output_t *out, pe_resource_t *rsc) {
if (rsc->children == NULL) {
out->list_item(out, "resource", "%s", rsc->id);
} else {
for (GListPtr lpc = rsc->children; lpc != NULL; lpc = lpc->next) {
pe_resource_t *child = (pe_resource_t *) lpc->data;
add_resource_name(out, child);
}
}
}
-PCMK__OUTPUT_ARGS("resource-names-list", "GListPtr")
+PCMK__OUTPUT_ARGS("resource-names-list", "GList *")
static int
resource_names(pcmk__output_t *out, va_list args) {
- GListPtr resources = va_arg(args, GListPtr);
+ GList *resources = va_arg(args, GList *);
if (resources == NULL) {
out->err(out, "NO resources configured\n");
return pcmk_rc_no_output;
}
out->begin_list(out, NULL, NULL, "Resource Names");
- for (GListPtr lpc = resources; lpc != NULL; lpc = lpc->next) {
+ for (GList *lpc = resources; lpc != NULL; lpc = lpc->next) {
pe_resource_t *rsc = (pe_resource_t *) lpc->data;
add_resource_name(out, rsc);
}
out->end_list(out);
return pcmk_rc_ok;
}
static pcmk__message_entry_t fmt_functions[] = {
{ "attribute", "default", attribute_default },
{ "attribute", "text", attribute_text },
{ "property", "default", property_default },
{ "property", "text", property_text },
{ "resource-check", "default", resource_check_default },
{ "resource-check", "xml", resource_check_xml },
{ "resource-search", "default", resource_search_default },
{ "resource-search", "xml", resource_search_xml },
{ "resource-why", "default", resource_why_default },
{ "resource-why", "xml", resource_why_xml },
{ "resource-names-list", "default", resource_names },
{ NULL, NULL, NULL }
};
void
crm_resource_register_messages(pcmk__output_t *out) {
pcmk__register_messages(out, fmt_functions);
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Apr 21, 6:18 PM (19 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1665190
Default Alt Text
(317 KB)

Event Timeline