diff --git a/include/crm/pengine/internal.h b/include/crm/pengine/internal.h index 31fee62911..75768a9e40 100644 --- a/include/crm/pengine/internal.h +++ b/include/crm/pengine/internal.h @@ -1,401 +1,398 @@ /* * Copyright 2004-2019 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #ifndef PE_INTERNAL__H # define PE_INTERNAL__H # include # include # include # include # define pe_rsc_info(rsc, fmt, args...) crm_log_tag(LOG_INFO, rsc ? rsc->id : "", fmt, ##args) # define pe_rsc_debug(rsc, fmt, args...) crm_log_tag(LOG_DEBUG, rsc ? rsc->id : "", fmt, ##args) # define pe_rsc_trace(rsc, fmt, args...) crm_log_tag(LOG_TRACE, rsc ? rsc->id : "", fmt, ##args) # define pe_err(fmt...) { was_processing_error = TRUE; crm_config_error = TRUE; crm_err(fmt); } # define pe_warn(fmt...) { was_processing_warning = TRUE; crm_config_warning = TRUE; crm_warn(fmt); } # define pe_proc_err(fmt...) { was_processing_error = TRUE; crm_err(fmt); } # define pe_proc_warn(fmt...) { was_processing_warning = TRUE; crm_warn(fmt); } # define pe_set_action_bit(action, bit) action->flags = crm_set_bit(__FUNCTION__, __LINE__, action->uuid, action->flags, bit) # define pe_clear_action_bit(action, bit) action->flags = crm_clear_bit(__FUNCTION__, __LINE__, action->uuid, action->flags, bit) typedef struct pe__location_constraint_s { char *id; // Constraint XML ID pe_resource_t *rsc_lh; // Resource being located enum rsc_role_e role_filter; // Role to locate enum pe_discover_e discover_mode; // Resource discovery GListPtr node_list_rh; // List of pe_node_t* } pe__location_t; typedef struct pe__order_constraint_s { int id; enum pe_ordering type; void *lh_opaque; resource_t *lh_rsc; action_t *lh_action; char *lh_action_task; void *rh_opaque; resource_t *rh_rsc; action_t *rh_action; char *rh_action_task; } pe__ordering_t; typedef struct notify_data_s { GSList *keys; // Environment variable name/value pairs const char *action; action_t *pre; action_t *post; action_t *pre_done; action_t *post_done; GListPtr active; /* notify_entry_t* */ GListPtr inactive; /* notify_entry_t* */ GListPtr start; /* notify_entry_t* */ GListPtr stop; /* notify_entry_t* */ GListPtr demote; /* notify_entry_t* */ GListPtr promote; /* notify_entry_t* */ GListPtr master; /* notify_entry_t* */ GListPtr slave; /* notify_entry_t* */ GHashTable *allowed_nodes; } notify_data_t; bool pe_can_fence(pe_working_set_t *data_set, node_t *node); int merge_weights(int w1, int w2); void add_hash_param(GHashTable * hash, const char *name, const char *value); char *native_parameter(resource_t * rsc, node_t * node, gboolean create, const char *name, pe_working_set_t * data_set); pe_node_t *native_location(const pe_resource_t *rsc, GList **list, int current); void pe_metadata(void); void verify_pe_options(GHashTable * options); void common_update_score(resource_t * rsc, const char *id, int score); void native_add_running(resource_t * rsc, node_t * node, pe_working_set_t * data_set); gboolean native_unpack(resource_t * rsc, pe_working_set_t * data_set); gboolean group_unpack(resource_t * rsc, pe_working_set_t * data_set); gboolean clone_unpack(resource_t * rsc, pe_working_set_t * data_set); gboolean pe__unpack_bundle(pe_resource_t *rsc, pe_working_set_t *data_set); resource_t *native_find_rsc(resource_t *rsc, const char *id, const node_t *node, int flags); gboolean native_active(resource_t * rsc, gboolean all); gboolean group_active(resource_t * rsc, gboolean all); gboolean clone_active(resource_t * rsc, gboolean all); gboolean pe__bundle_active(pe_resource_t *rsc, gboolean all); void native_print(resource_t * rsc, const char *pre_text, long options, void *print_data); void group_print(resource_t * rsc, const char *pre_text, long options, void *print_data); void clone_print(resource_t * rsc, const char *pre_text, long options, void *print_data); void pe__print_bundle(pe_resource_t *rsc, const char *pre_text, long options, void *print_data); int pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name , size_t pairs_count, ...); int pe__clone_xml(pcmk__output_t *out, va_list args); int pe__clone_html(pcmk__output_t *out, va_list args); int pe__clone_text(pcmk__output_t *out, va_list args); int pe__bundle_xml(pcmk__output_t *out, va_list args); int pe__bundle_html(pcmk__output_t *out, va_list args); int pe__bundle_text(pcmk__output_t *out, va_list args); int pe__resource_xml(pcmk__output_t *out, va_list args); int pe__resource_html(pcmk__output_t *out, va_list args); int pe__resource_text(pcmk__output_t *out, va_list args); void native_free(resource_t * rsc); void group_free(resource_t * rsc); void clone_free(resource_t * rsc); void pe__free_bundle(pe_resource_t *rsc); enum rsc_role_e native_resource_state(const resource_t * rsc, gboolean current); enum rsc_role_e group_resource_state(const resource_t * rsc, gboolean current); enum rsc_role_e clone_resource_state(const resource_t * rsc, gboolean current); enum rsc_role_e pe__bundle_resource_state(const pe_resource_t *rsc, gboolean current); gboolean common_unpack(xmlNode * xml_obj, resource_t ** rsc, resource_t * parent, pe_working_set_t * data_set); void common_free(resource_t * rsc); extern node_t *node_copy(const node_t *this_node); extern time_t get_effective_time(pe_working_set_t * data_set); /* Failure handling utilities (from failcounts.c) */ // bit flags for fail count handling options enum pe_fc_flags_e { pe_fc_default = 0x00, pe_fc_effective = 0x01, // don't count expired failures pe_fc_fillers = 0x02, // if container, include filler failures in count }; int pe_get_failcount(node_t *node, resource_t *rsc, time_t *last_failure, uint32_t flags, xmlNode *xml_op, pe_working_set_t *data_set); pe_action_t *pe__clear_failcount(pe_resource_t *rsc, pe_node_t *node, const char *reason, pe_working_set_t *data_set); /* Functions for finding/counting a resource's active nodes */ pe_node_t *pe__find_active_on(const pe_resource_t *rsc, unsigned int *count_all, unsigned int *count_clean); pe_node_t *pe__find_active_requires(const pe_resource_t *rsc, unsigned int *count); static inline pe_node_t * pe__current_node(const pe_resource_t *rsc) { return pe__find_active_on(rsc, NULL, NULL); } /* Binary like operators for lists of nodes */ extern void node_list_exclude(GHashTable * list, GListPtr list2, gboolean merge_scores); extern GListPtr node_list_dup(GListPtr list, gboolean reset, gboolean filter); extern GHashTable *node_hash_from_list(GListPtr list); static inline gpointer pe_hash_table_lookup(GHashTable * hash, gconstpointer key) { if (hash) { return g_hash_table_lookup(hash, key); } return NULL; } extern action_t *get_pseudo_op(const char *name, pe_working_set_t * data_set); extern gboolean order_actions(action_t * lh_action, action_t * rh_action, enum pe_ordering order); GHashTable *node_hash_dup(GHashTable * hash); /* Printing functions for debug */ extern void print_node(const char *pre_text, node_t * node, gboolean details); extern void print_str_str(gpointer key, gpointer value, gpointer user_data); extern void pe__output_node(node_t * node, gboolean details, pcmk__output_t *out); extern void print_resource(int log_level, const char *pre_text, resource_t * rsc, gboolean details); extern void pe__output_resource(int log_level, resource_t * rsc, gboolean details, pcmk__output_t *out); extern void dump_node_scores_worker(int level, const char *file, const char *function, int line, resource_t * rsc, const char *comment, GHashTable * nodes); extern void dump_node_capacity(int level, const char *comment, node_t * node); extern void dump_rsc_utilization(int level, const char *comment, resource_t * rsc, node_t * node); # define dump_node_scores(level, rsc, text, nodes) do { \ dump_node_scores_worker(level, __FILE__, __FUNCTION__, __LINE__, rsc, text, nodes); \ } while(0) /* Sorting functions */ extern gint sort_rsc_priority(gconstpointer a, gconstpointer b); extern gint sort_rsc_index(gconstpointer a, gconstpointer b); extern xmlNode *find_rsc_op_entry(resource_t * rsc, const char *key); extern action_t *custom_action(resource_t * rsc, char *key, const char *task, node_t * on_node, gboolean optional, gboolean foo, pe_working_set_t * data_set); # define delete_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_DELETE, 0) # define delete_action(rsc, node, optional) custom_action( \ rsc, delete_key(rsc), CRMD_ACTION_DELETE, node, \ optional, TRUE, data_set); # define stopped_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STOPPED, 0) # define stopped_action(rsc, node, optional) custom_action( \ rsc, stopped_key(rsc), CRMD_ACTION_STOPPED, node, \ optional, TRUE, data_set); # define stop_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STOP, 0) # define stop_action(rsc, node, optional) custom_action( \ rsc, stop_key(rsc), CRMD_ACTION_STOP, node, \ optional, TRUE, data_set); # define reload_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_RELOAD, 0) # define start_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_START, 0) # define start_action(rsc, node, optional) custom_action( \ rsc, start_key(rsc), CRMD_ACTION_START, node, \ optional, TRUE, data_set) # define started_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STARTED, 0) # define started_action(rsc, node, optional) custom_action( \ rsc, started_key(rsc), CRMD_ACTION_STARTED, node, \ optional, TRUE, data_set) # define promote_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_PROMOTE, 0) # define promote_action(rsc, node, optional) custom_action( \ rsc, promote_key(rsc), CRMD_ACTION_PROMOTE, node, \ optional, TRUE, data_set) # define promoted_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_PROMOTED, 0) # define promoted_action(rsc, node, optional) custom_action( \ rsc, promoted_key(rsc), CRMD_ACTION_PROMOTED, node, \ optional, TRUE, data_set) # define demote_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_DEMOTE, 0) # define demote_action(rsc, node, optional) custom_action( \ rsc, demote_key(rsc), CRMD_ACTION_DEMOTE, node, \ optional, TRUE, data_set) # define demoted_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_DEMOTED, 0) # define demoted_action(rsc, node, optional) custom_action( \ rsc, demoted_key(rsc), CRMD_ACTION_DEMOTED, node, \ optional, TRUE, data_set) extern int pe_get_configured_timeout(resource_t *rsc, const char *action, pe_working_set_t *data_set); extern action_t *find_first_action(GListPtr input, const char *uuid, const char *task, node_t * on_node); extern enum action_tasks get_complex_task(resource_t * rsc, const char *name, gboolean allow_non_atomic); extern GListPtr find_actions(GListPtr input, const char *key, const node_t *on_node); GList *find_actions_exact(GList *input, const char *key, const pe_node_t *on_node); extern GListPtr find_recurring_actions(GListPtr input, node_t * not_on_node); GList *pe__resource_actions(const pe_resource_t *rsc, const pe_node_t *node, const char *task, bool require_node); extern void pe_free_action(action_t * action); extern void resource_location(resource_t * rsc, node_t * node, int score, const char *tag, pe_working_set_t * data_set); extern gint sort_op_by_callid(gconstpointer a, gconstpointer b); extern gboolean get_target_role(resource_t * rsc, enum rsc_role_e *role); extern resource_t *find_clone_instance(resource_t * rsc, const char *sub_id, pe_working_set_t * data_set); extern void destroy_ticket(gpointer data); extern ticket_t *ticket_new(const char *ticket_id, pe_working_set_t * data_set); // Resources for manipulating resource names const char *pe_base_name_end(const char *id); char *clone_strip(const char *last_rsc_id); char *clone_zero(const char *last_rsc_id); static inline bool pe_base_name_eq(resource_t *rsc, const char *id) { if (id && rsc && rsc->id) { // Number of characters in rsc->id before any clone suffix size_t base_len = pe_base_name_end(rsc->id) - rsc->id + 1; return (strlen(id) == base_len) && !strncmp(id, rsc->id, base_len); } return FALSE; } int pe__target_rc_from_xml(xmlNode *xml_op); gint sort_node_uname(gconstpointer a, gconstpointer b); bool is_set_recursive(resource_t * rsc, long long flag, bool any); enum rsc_digest_cmp_val { /*! Digests are the same */ RSC_DIGEST_MATCH = 0, /*! Params that require a restart changed */ RSC_DIGEST_RESTART, /*! Some parameter changed. */ RSC_DIGEST_ALL, /*! rsc op didn't have a digest associated with it, so * it is unknown if parameters changed or not. */ RSC_DIGEST_UNKNOWN, }; typedef struct op_digest_cache_s { enum rsc_digest_cmp_val rc; xmlNode *params_all; xmlNode *params_secure; xmlNode *params_restart; char *digest_all_calc; char *digest_secure_calc; char *digest_restart_calc; } op_digest_cache_t; op_digest_cache_t *rsc_action_digest_cmp(resource_t * rsc, xmlNode * xml_op, node_t * node, pe_working_set_t * data_set); action_t *pe_fence_op(node_t * node, const char *op, bool optional, const char *reason, pe_working_set_t * data_set); void trigger_unfencing( resource_t * rsc, node_t *node, const char *reason, action_t *dependency, pe_working_set_t * data_set); void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite); void pe_action_set_flag_reason(const char *function, long line, pe_action_t *action, pe_action_t *reason, const char *text, enum pe_action_flags flags, bool overwrite); #define pe_action_required(action, reason, text) pe_action_set_flag_reason(__FUNCTION__, __LINE__, action, reason, text, pe_action_optional, FALSE) #define pe_action_implies(action, reason, flag) pe_action_set_flag_reason(__FUNCTION__, __LINE__, action, reason, NULL, flag, FALSE) void set_bit_recursive(resource_t * rsc, unsigned long long flag); void clear_bit_recursive(resource_t * rsc, unsigned long long flag); gboolean add_tag_ref(GHashTable * tags, const char * tag_name, const char * obj_ref); void print_rscs_brief(GListPtr rsc_list, const char * pre_text, long options, void * print_data, gboolean print_all); -void pe__rscs_brief_output_text(pcmk__output_t *out, GListPtr rsc_list, - long options, gboolean print_all); -void pe__rscs_brief_output_html(pcmk__output_t *out, GListPtr rsc_list, - long options, gboolean print_all); +void pe__rscs_brief_output(pcmk__output_t *out, GListPtr rsc_list, long options, gboolean print_all); void pe_fence_node(pe_working_set_t * data_set, node_t * node, const char *reason); node_t *pe_create_node(const char *id, const char *uname, const char *type, const char *score, pe_working_set_t * data_set); bool remote_id_conflict(const char *remote_name, pe_working_set_t *data); void common_print(resource_t * rsc, const char *pre_text, const char *name, node_t *node, long options, void *print_data); void pe__common_output_text(pcmk__output_t *out, resource_t * rsc, const char *name, node_t *node, long options); void pe__common_output_html(pcmk__output_t *out, resource_t * rsc, const char *name, node_t *node, long options); pe_resource_t *pe__find_bundle_replica(const pe_resource_t *bundle, const pe_node_t *node); bool pe__bundle_needs_remote_name(pe_resource_t *rsc); const char *pe__add_bundle_remote_name(pe_resource_t *rsc, xmlNode *xml, const char *field); const char *pe_node_attribute_calculated(const pe_node_t *node, const char *name, const resource_t *rsc); const char *pe_node_attribute_raw(pe_node_t *node, const char *name); bool pe__is_universal_clone(pe_resource_t *rsc, pe_working_set_t *data_set); void pe__add_param_check(xmlNode *rsc_op, pe_resource_t *rsc, pe_node_t *node, enum pe_check_parameters, pe_working_set_t *data_set); void pe__foreach_param_check(pe_working_set_t *data_set, void (*cb)(pe_resource_t*, pe_node_t*, xmlNode*, enum pe_check_parameters, pe_working_set_t*)); void pe__free_param_checks(pe_working_set_t *data_set); bool pe__shutdown_requested(pe_node_t *node); void pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set); #define BOOL2STR(x) ((x) ? "true" : "false") /*! * \internal * \brief Register xml formatting message functions. */ void pe__register_messages(pcmk__output_t *out); void pe__unpack_dataset_nvpairs(xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, gboolean overwrite, pe_working_set_t *data_set); #endif diff --git a/lib/pengine/native.c b/lib/pengine/native.c index 58d3251b90..e9f87099c2 100644 --- a/lib/pengine/native.c +++ b/lib/pengine/native.c @@ -1,1544 +1,1483 @@ /* * Copyright 2004-2019 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #include #include #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; } void native_add_running(resource_t * rsc, 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) { node_t *a_node = (node_t *) gIter->data; CRM_CHECK(a_node != NULL, return); if (safe_str_eq(a_node->details->id, node->details->id)) { return; } } pe_rsc_trace(rsc, "Adding %s to %s %s", rsc->id, node->details->uname, 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); } if (rsc->variant == pe_native && node->details->maintenance) { clear_bit(rsc->flags, pe_rsc_managed); } if (is_not_set(rsc->flags, pe_rsc_managed)) { 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; 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 = node_hash_from_list(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: clear_bit(rsc->flags, pe_rsc_managed); set_bit(rsc->flags, 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) { resource_t *child = (resource_t *) gIter->data; clear_bit(child->flags, pe_rsc_managed); set_bit(child->flags, 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) { clear_bit(rsc->flags, 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(resource_t * rsc, pe_working_set_t * data_set) { 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 (is_not_set(ra_caps, pcmk_ra_cap_unique) && 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 (is_not_set(ra_caps, pcmk_ra_cap_promotable) && 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(resource_t *rsc, const node_t *node, int flags) { pe_rsc_trace(rsc, "Checking whether %s is on %s", rsc->id, node->details->uname); if (is_set(flags, pe_find_current) && rsc->running_on) { for (GListPtr iter = rsc->running_on; iter; iter = iter->next) { node_t *loc = (node_t *) iter->data; if (loc->details == node->details) { return TRUE; } } } else if (is_set(flags, pe_find_inactive) && (rsc->running_on == NULL)) { return TRUE; } else if (is_not_set(flags, pe_find_current) && rsc->allocated_to && (rsc->allocated_to->details == node->details)) { return TRUE; } return FALSE; } resource_t * native_find_rsc(resource_t * rsc, const char *id, const node_t *on_node, int flags) { bool match = FALSE; 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) || safe_str_eq(id, rid)) { match = TRUE; } } else if (!strcmp(id, rsc->id)) { match = TRUE; } else if (is_set(flags, pe_find_renamed) && rsc->clone_name && strcmp(rsc->clone_name, id) == 0) { match = TRUE; } else if (is_set(flags, pe_find_any) || (is_set(flags, pe_find_anon) && is_not_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) { resource_t *child = (resource_t *) gIter->data; result = rsc->fns->find_rsc(child, id, on_node, flags); if (result) { return result; } } return NULL; } char * native_parameter(resource_t * rsc, 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(resource_t * rsc, gboolean all) { GListPtr gIter = rsc->running_on; for (; gIter != NULL; gIter = gIter->next) { node_t *a_node = (node_t *) gIter->data; if (a_node->details->unclean) { crm_debug("Resource %s: node %s is unclean", rsc->id, a_node->details->uname); return TRUE; } else if (a_node->details->online == FALSE) { crm_debug("Resource %s: node %s is offline", rsc->id, a_node->details->uname); } else { crm_debug("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 void native_print_attr(gpointer key, gpointer value, gpointer user_data) { long options = ((struct print_data_s *)user_data)->options; void *print_data = ((struct print_data_s *)user_data)->print_data; status_print("Option: %s = %s\n", (char *)key, (char *)value); } static const char * native_pending_state(resource_t * rsc) { const char *pending_state = NULL; if (safe_str_eq(rsc->pending_task, CRMD_ACTION_START)) { pending_state = "Starting"; } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_STOP)) { pending_state = "Stopping"; } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_MIGRATE)) { pending_state = "Migrating"; } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_MIGRATED)) { /* Work might be done in here. */ pending_state = "Migrating"; } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_PROMOTE)) { pending_state = "Promoting"; } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_DEMOTE)) { pending_state = "Demoting"; } return pending_state; } static const char * native_pending_task(resource_t * rsc) { const char *pending_task = NULL; if (safe_str_eq(rsc->pending_task, CRMD_ACTION_STATUS)) { 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 (safe_str_eq(rsc->pending_task, "probe")) { pending_task = "Checking"; */ } return pending_task; } static enum rsc_role_e native_displayable_role(resource_t *rsc) { enum rsc_role_e role = rsc->role; if ((role == RSC_ROLE_STARTED) && is_set(uber_parent(rsc)->flags, pe_rsc_promotable)) { role = RSC_ROLE_SLAVE; } return role; } static const char * native_displayable_state(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(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("%sxml, 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\" ", rsc->fns->active(rsc, TRUE) ? "true" : "false"); status_print("orphaned=\"%s\" ", is_set(rsc->flags, pe_rsc_orphan) ? "true" : "false"); status_print("blocked=\"%s\" ", is_set(rsc->flags, pe_rsc_block) ? "true" : "false"); status_print("managed=\"%s\" ", is_set(rsc->flags, pe_rsc_managed) ? "true" : "false"); status_print("failed=\"%s\" ", is_set(rsc->flags, pe_rsc_failed) ? "true" : "false"); status_print("failure_ignored=\"%s\" ", is_set(rsc->flags, pe_rsc_failure_ignored) ? "true" : "false"); 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); } } if (options & pe_print_dev) { status_print("provisional=\"%s\" ", is_set(rsc->flags, pe_rsc_provisional) ? "true" : "false"); status_print("runnable=\"%s\" ", is_set(rsc->flags, pe_rsc_runnable) ? "true" : "false"); status_print("priority=\"%f\" ", (double)rsc->priority); status_print("variant=\"%s\" ", crm_element_name(rsc->xml)); } /* 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) { node_t *node = (node_t *) gIter->data; status_print("%s \n", pre_text, node->details->uname, node->details->id, node->details->online ? "false" : "true"); } status_print("%s\n", pre_text); } else { status_print("/>\n"); } } /* making this inline rather than a macro prevents a coverity "unreachable" * warning on the first usage */ static inline const char * comma_if(int i) { return i? ", " : ""; } static char * flags_string(resource_t *rsc, node_t *node, long options, const char *target_role) { gchar **flags = calloc(6, sizeof(gchar *)); int ndx = 0; if (node && node->details->online == FALSE && node->details->unclean) { flags[ndx] = strdup("UNCLEAN"); ndx++; } if (is_set(options, pe_print_pending)) { const char *pending_task = native_pending_task(rsc); if (pending_task) { flags[ndx] = strdup(pending_task); ndx++; } } if (target_role) { enum rsc_role_e target_role_e = text2role(target_role); /* Ignore target role Started, as it is the default anyways * (and would also allow a Master to be Master). * Show if target role limits our abilities. */ if (target_role_e == RSC_ROLE_STOPPED) { flags[ndx] = strdup("disabled"); ndx++; rsc->cluster->disabled_resources++; } else if (is_set(uber_parent(rsc)->flags, pe_rsc_promotable) && target_role_e == RSC_ROLE_SLAVE) { flags[ndx] = crm_strdup_printf("target-role:%s", target_role); ndx++; rsc->cluster->disabled_resources++; } } if (is_set(rsc->flags, pe_rsc_block)) { flags[ndx] = strdup("blocked"); ndx++; rsc->cluster->blocked_resources++; } else if (is_not_set(rsc->flags, pe_rsc_managed)) { flags[ndx] = strdup("unmanaged"); ndx++; } if (is_set(rsc->flags, pe_rsc_failure_ignored)) { flags[ndx] = strdup("failure ignored"); } if (flags[0] != NULL) { char *total = g_strjoinv(" ", flags); char *flags_s = crm_strdup_printf(" (%s)", total); g_free(total); g_strfreev(flags); return flags_s; } return NULL; } static char * native_output_string(resource_t *rsc, const char *name, node_t *node, long options, const char *target_role) { const char *desc = NULL; const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE); enum rsc_role_e role = native_displayable_role(rsc); char *retval = NULL; char *unames = NULL; char *provider = NULL; const char *orphan = NULL; char *role_s = NULL; char *node_s = NULL; char *print_dev_s = NULL; char *flags_s = NULL; CRM_ASSERT(kind != NULL); if (is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) { provider = crm_strdup_printf("::%s", crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER)); } if (is_set(rsc->flags, pe_rsc_orphan)) { orphan = " ORPHANED"; } if (role > RSC_ROLE_SLAVE && is_set(rsc->flags, pe_rsc_failed)) { role_s = crm_strdup_printf(" FAILED %s", role2text(role)); } else if (is_set(rsc->flags, pe_rsc_failed)) { role_s = crm_strdup_printf(" FAILED"); } else { role_s = crm_strdup_printf(" %s", native_displayable_state(rsc, options)); } if (node) { node_s = crm_strdup_printf(" %s", node->details->uname); } if (is_set(options, pe_print_rsconly) || g_list_length(rsc->running_on) > 1) { desc = crm_element_value(rsc->xml, XML_ATTR_DESC); } if (is_not_set(options, pe_print_rsconly) && g_list_length(rsc->running_on) > 1) { GListPtr gIter = rsc->running_on; gchar **arr = calloc(g_list_length(rsc->running_on)+1, sizeof(gchar *)); int i = 0; char *total = NULL; for (; gIter != NULL; gIter = gIter->next) { node_t *n = (node_t *) gIter->data; arr[i] = (gchar *) strdup(n->details->uname); i++; } total = g_strjoinv(" ", arr); unames = crm_strdup_printf(" [ %s ]", total); g_free(total); g_strfreev(arr); } if (is_set(options, pe_print_dev)) { print_dev_s = crm_strdup_printf(" (%s%svariant=%s, priority=%f)", is_set(rsc->flags, pe_rsc_provisional) ? "provisional, " : "", is_set(rsc->flags, pe_rsc_runnable) ? "" : "non-startable, ", crm_element_name(rsc->xml), (double)rsc->priority); } flags_s = flags_string(rsc, node, options, target_role); retval = crm_strdup_printf("%s\t(%s%s:%s):\t%s%s%s%s%s%s%s%s", name, class, provider ? provider : "", kind, orphan ? orphan : "", role_s, node_s ? node_s : "", print_dev_s ? print_dev_s : "", flags_s ? flags_s : "", desc ? " " : "", desc ? desc : "", unames ? unames : ""); free(provider); free(role_s); free(node_s); free(unames); free(print_dev_s); free(flags_s); return retval; } void pe__common_output_html(pcmk__output_t *out, resource_t * rsc, const char *name, node_t *node, long options) { char *s = NULL; const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE); const char *target_role = NULL; const char *color = 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) && is_not_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_rsconly) || g_list_length(rsc->running_on) > 1) { node = NULL; } pcmk__output_xml_create_parent(out, "font"); if (is_not_set(rsc->flags, pe_rsc_managed)) { color = "yellow"; } else if (is_set(rsc->flags, pe_rsc_failed)) { color = "red"; } else if (rsc->variant == pe_native && (rsc->running_on == NULL)) { color = "red"; } else if (g_list_length(rsc->running_on) > 1) { color = "orange"; } else if (is_set(rsc->flags, pe_rsc_failure_ignored)) { color = "yellow"; } else { color = "green"; } xmlSetProp(pcmk__output_xml_peek_parent(out), (pcmkXmlStr)"color", (pcmkXmlStr)color); s = native_output_string(rsc, name, node, options, target_role); xmlNodeSetContent(pcmk__output_xml_peek_parent(out), (pcmkXmlStr)s); free(s); pcmk__output_create_xml_node(out, "br"); if (is_set(options, pe_print_details)) { GHashTableIter iter; gpointer key, value; out->begin_list(out, NULL, NULL, "Options"); g_hash_table_iter_init(&iter, rsc->parameters); while (g_hash_table_iter_next(&iter, &key, &value)) { out->list_item(out, NULL, "Option: %s = %s", (char *) key, (char *) value); } out->end_list(out); } if (is_set(options, pe_print_dev)) { GHashTableIter iter; node_t *n = NULL; out->begin_list(out, NULL, NULL, "Allowed Nodes"); g_hash_table_iter_init(&iter, rsc->allowed_nodes); while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) { out->list_item(out, NULL, "%s %d", n->details->uname, n->weight); } out->end_list(out); } if (is_set(options, pe_print_max_details)) { GHashTableIter iter; node_t *n = NULL; out->begin_list(out, NULL, NULL, "=== Allowed Nodes"); g_hash_table_iter_init(&iter, rsc->allowed_nodes); while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) { pe__output_node(n, FALSE, out); } out->end_list(out); } } void pe__common_output_text(pcmk__output_t *out, resource_t * rsc, const char *name, node_t *node, long options) { char *s = NULL; 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) && is_not_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 (is_set(options, pe_print_rsconly) || g_list_length(rsc->running_on) > 1) { node = NULL; } s = native_output_string(rsc, name, node, options, target_role); out->list_item(out, NULL, "%s", s); free(s); if (is_set(options, pe_print_details)) { GHashTableIter iter; gpointer key, value; out->begin_list(out, NULL, NULL, "Options"); g_hash_table_iter_init(&iter, rsc->parameters); while (g_hash_table_iter_next(&iter, &key, &value)) { out->list_item(out, NULL, "Option: %s = %s", (char *) key, (char *) value); } out->end_list(out); } if (is_set(options, pe_print_dev)) { GHashTableIter iter; node_t *n = NULL; out->begin_list(out, NULL, NULL, "Allowed Nodes"); g_hash_table_iter_init(&iter, rsc->allowed_nodes); while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) { out->list_item(out, NULL, "%s %d", n->details->uname, n->weight); } out->end_list(out); } if (is_set(options, pe_print_max_details)) { GHashTableIter iter; node_t *n = NULL; out->begin_list(out, NULL, NULL, "=== Allowed Nodes"); g_hash_table_iter_init(&iter, rsc->allowed_nodes); while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) { pe__output_node(n, FALSE, out); } out->end_list(out); } } void common_print(resource_t * rsc, const char *pre_text, const char *name, node_t *node, long options, void *print_data) { const char *desc = NULL; const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE); const char *target_role = NULL; enum rsc_role_e role = native_displayable_role(rsc); int offset = 0; int flagOffset = 0; char buffer[LINE_MAX]; char flagBuffer[LINE_MAX]; 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) && is_not_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 (pre_text == NULL && (options & pe_print_printf)) { pre_text = " "; } if (options & pe_print_xml) { native_print_xml(rsc, pre_text, options, print_data); return; } if ((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) { node = NULL; } if (options & pe_print_html) { if (is_not_set(rsc->flags, pe_rsc_managed)) { status_print(""); } else if (is_set(rsc->flags, pe_rsc_failed)) { status_print(""); } else if (rsc->variant == pe_native && (rsc->running_on == NULL)) { status_print(""); } else if (g_list_length(rsc->running_on) > 1) { status_print(""); } else if (is_set(rsc->flags, pe_rsc_failure_ignored)) { status_print(""); } else { status_print(""); } } if(pre_text) { offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", pre_text); } offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", name); offset += snprintf(buffer + offset, LINE_MAX - offset, "\t(%s", class); if (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):\t", kind); if(is_set(rsc->flags, pe_rsc_orphan)) { offset += snprintf(buffer + offset, LINE_MAX - offset, " ORPHANED "); } if(role > RSC_ROLE_SLAVE && is_set(rsc->flags, pe_rsc_failed)) { offset += snprintf(buffer + offset, LINE_MAX - offset, "FAILED %s", role2text(role)); } else if(is_set(rsc->flags, pe_rsc_failed)) { offset += snprintf(buffer + offset, LINE_MAX - offset, "FAILED"); } else { const char *rsc_state = native_displayable_state(rsc, options); offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", rsc_state); } if(node) { offset += snprintf(buffer + offset, LINE_MAX - offset, " %s", node->details->uname); if (node->details->online == FALSE && node->details->unclean) { flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset, "%sUNCLEAN", comma_if(flagOffset)); } } if (options & pe_print_pending) { const char *pending_task = native_pending_task(rsc); if (pending_task) { flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset, "%s%s", comma_if(flagOffset), pending_task); } } if (target_role) { enum rsc_role_e target_role_e = text2role(target_role); /* Ignore target role Started, as it is the default anyways * (and would also allow a Master to be Master). * Show if target role limits our abilities. */ if (target_role_e == RSC_ROLE_STOPPED) { flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset, "%sdisabled", comma_if(flagOffset)); rsc->cluster->disabled_resources++; } else if (is_set(uber_parent(rsc)->flags, pe_rsc_promotable) && target_role_e == RSC_ROLE_SLAVE) { flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset, "%starget-role:%s", comma_if(flagOffset), target_role); rsc->cluster->disabled_resources++; } } if (is_set(rsc->flags, pe_rsc_block)) { flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset, "%sblocked", comma_if(flagOffset)); rsc->cluster->blocked_resources++; } else if (is_not_set(rsc->flags, pe_rsc_managed)) { flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset, "%sunmanaged", comma_if(flagOffset)); } if(is_set(rsc->flags, pe_rsc_failure_ignored)) { flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset, "%sfailure ignored", comma_if(flagOffset)); } if ((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) { desc = crm_element_value(rsc->xml, XML_ATTR_DESC); } CRM_LOG_ASSERT(offset > 0); if(flagOffset > 0) { status_print("%s (%s)%s%s", buffer, flagBuffer, desc?" ":"", desc?desc:""); } else { status_print("%s%s%s", buffer, desc?" ":"", desc?desc:""); } #if CURSES_ENABLED if ((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) { /* Done */ } else if (options & pe_print_ncurses) { /* coverity[negative_returns] False positive */ move(-1, 0); } #endif if (options & pe_print_html) { status_print(" "); } if ((options & pe_print_rsconly)) { } else if (g_list_length(rsc->running_on) > 1) { GListPtr gIter = rsc->running_on; int counter = 0; if (options & pe_print_html) { status_print("
    \n"); } else if ((options & pe_print_printf) || (options & pe_print_ncurses)) { status_print("["); } for (; gIter != NULL; gIter = gIter->next) { node_t *n = (node_t *) gIter->data; counter++; if (options & pe_print_html) { status_print("
  • \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("
  • \n"); } } if (options & pe_print_html) { status_print("
\n"); } else if ((options & pe_print_printf) || (options & pe_print_ncurses)) { status_print(" ]"); } } if (options & pe_print_html) { status_print("
\n"); } else if (options & pe_print_suppres_nl) { /* nothing */ } else if ((options & pe_print_printf) || (options & pe_print_ncurses)) { status_print("\n"); } if (options & pe_print_details) { struct print_data_s pdata; pdata.options = options; pdata.print_data = print_data; g_hash_table_foreach(rsc->parameters, native_print_attr, &pdata); } if (options & pe_print_dev) { GHashTableIter iter; node_t *n = NULL; status_print("%s\t(%s%svariant=%s, priority=%f)", pre_text, is_set(rsc->flags, pe_rsc_provisional) ? "provisional, " : "", is_set(rsc->flags, pe_rsc_runnable) ? "" : "non-startable, ", crm_element_name(rsc->xml), (double)rsc->priority); status_print("%s\tAllowed Nodes", pre_text); g_hash_table_iter_init(&iter, rsc->allowed_nodes); while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) { status_print("%s\t * %s %d", pre_text, n->details->uname, n->weight); } } if (options & pe_print_max_details) { GHashTableIter iter; node_t *n = NULL; status_print("%s\t=== Allowed Nodes\n", pre_text); g_hash_table_iter_init(&iter, rsc->allowed_nodes); while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) { print_node("\t", n, FALSE); } } } void native_print(resource_t * rsc, const char *pre_text, long options, void *print_data) { 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); } int pe__resource_xml(pcmk__output_t *out, va_list args) { long options = va_arg(args, int); resource_t *rsc = va_arg(args, resource_t *); 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; long is_print_dev = options & pe_print_dev; char ra_name[LINE_MAX]; char *nodes_running_on = NULL; char *priority = NULL; int rc = 0; CRM_ASSERT(rsc->variant == pe_native); /* 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", 16 , "id", rsc_printable_id(rsc) , "resource_agent", ra_name , "role", rsc_state , "target_role", (rsc->meta ? g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE) : NULL) , "active", BOOL2STR(rsc->fns->active(rsc, TRUE)) , "orphaned", BOOL2STR(is_set(rsc->flags, pe_rsc_orphan)) , "blocked", BOOL2STR(is_set(rsc->flags, pe_rsc_block)) , "managed", BOOL2STR(is_set(rsc->flags, pe_rsc_managed)) , "failed", BOOL2STR(is_set(rsc->flags, pe_rsc_failed)) , "failure_ignored", BOOL2STR(is_set(rsc->flags, pe_rsc_failure_ignored)) , "nodes_running_on", nodes_running_on , "pending", (is_print_pending ? native_pending_task(rsc) : NULL) , "provisional", (is_print_dev ? BOOL2STR(is_set(rsc->flags, pe_rsc_provisional)) : NULL) , "runnable", (is_print_dev ? BOOL2STR(is_set(rsc->flags, pe_rsc_runnable)) : NULL) , "priority", (is_print_dev ? priority : NULL) , "variant", (is_print_dev ? crm_element_name(rsc->xml) : NULL)); free(priority); free(nodes_running_on); CRM_ASSERT(rc == 0); if (rsc->running_on != NULL) { GListPtr gIter = rsc->running_on; for (; gIter != NULL; gIter = gIter->next) { node_t *node = (node_t *) gIter->data; rc = pe__name_and_nvpairs_xml(out, false, "node", 3 , "name", node->details->uname , "id", node->details->id , "cached", BOOL2STR(node->details->online)); CRM_ASSERT(rc == 0); } } pcmk__output_xml_pop_parent(out); return rc; } int pe__resource_html(pcmk__output_t *out, va_list args) { long options = va_arg(args, int); resource_t *rsc = va_arg(args, resource_t *); node_t *node = pe__current_node(rsc); 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; } pe__common_output_html(out, rsc, rsc_printable_id(rsc), node, options); return 0; } int pe__resource_text(pcmk__output_t *out, va_list args) { long options = va_arg(args, int); resource_t *rsc = va_arg(args, resource_t *); node_t *node = pe__current_node(rsc); 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; } pe__common_output_text(out, rsc, rsc_printable_id(rsc), node, options); return 0; } void native_free(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 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) { node_t *one = NULL; GListPtr result = NULL; if (rsc->children) { GListPtr gIter = rsc->children; for (; gIter != NULL; gIter = gIter->next) { resource_t *child = (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) { node_t *node = (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) { resource_t *rsc = (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 (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) { node_t *node = (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("
  • \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("
  • \n"); } } if (print_all && active_counter_all == 0) { if (options & pe_print_html) { status_print("
  • \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("
  • \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; } } void -pe__rscs_brief_output_text(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); - 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 (print_all) { - pcmk__indented_printf(out, "%d/%d\t(%s):\tActive %s\n", *active_counter, - rsc_counter ? *rsc_counter : 0, type, - (*active_counter > 0) && node_name ? node_name : ""); - } else { - pcmk__indented_printf(out, "%d\t(%s):\tActive %s\n", *active_counter, type, - (*active_counter > 0) && node_name ? node_name : ""); - } - } - - if (print_all && active_counter_all == 0) { - pcmk__indented_printf(out, "%d/%d\t(%s):\tActive\n", active_counter_all, - rsc_counter ? *rsc_counter : 0, type); - } - } - - if (rsc_table) { - g_hash_table_destroy(rsc_table); - rsc_table = NULL; - } - if (active_table) { - g_hash_table_destroy(active_table); - active_table = NULL; - } -} - -void -pe__rscs_brief_output_html(pcmk__output_t *out, GListPtr rsc_list, long options, gboolean print_all) +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); 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 (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 : ""); } } 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); } } if (rsc_table) { g_hash_table_destroy(rsc_table); rsc_table = NULL; } if (active_table) { g_hash_table_destroy(active_table); active_table = NULL; } } diff --git a/lib/pengine/pe_output.c b/lib/pengine/pe_output.c index d1d4b3cb05..f94f96e4bc 100644 --- a/lib/pengine/pe_output.c +++ b/lib/pengine/pe_output.c @@ -1,244 +1,244 @@ /* * Copyright 2019 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #include #include #include 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) { xmlSetProp(xml_node, (pcmkXmlStr)param_name, (pcmkXmlStr)param_value); } }; va_end(args); if (is_list) { pcmk__output_xml_push_parent(out, xml_node); } return 0; } static int pe__group_xml(pcmk__output_t *out, va_list args) { long options = va_arg(args, long); resource_t *rsc = va_arg(args, resource_t *); GListPtr gIter = rsc->children; char *count = crm_itoa(g_list_length(gIter)); int rc = pe__name_and_nvpairs_xml(out, true, "group", 2 , "id", rsc->id , "number_resources", count); free(count); CRM_ASSERT(rc == 0); for (; gIter != NULL; gIter = gIter->next) { resource_t *child_rsc = (resource_t *) gIter->data; out->message(out, crm_element_name(child_rsc->xml), options, child_rsc); } pcmk__output_xml_pop_parent(out); return rc; } static int pe__group_html(pcmk__output_t *out, va_list args) { long options = va_arg(args, long); resource_t *rsc = va_arg(args, resource_t *); out->begin_list(out, NULL, NULL, "Resource Group: %s", rsc->id); if (options & pe_print_brief) { - pe__rscs_brief_output_html(out, rsc->children, options, TRUE); + pe__rscs_brief_output(out, rsc->children, options, TRUE); } else { for (GListPtr gIter = rsc->children; gIter; gIter = gIter->next) { resource_t *child_rsc = (resource_t *) gIter->data; out->message(out, crm_element_name(child_rsc->xml), options, child_rsc); } } out->end_list(out); return 0; } static int pe__group_text(pcmk__output_t *out, va_list args) { long options = va_arg(args, long); resource_t *rsc = va_arg(args, resource_t *); out->begin_list(out, NULL, NULL, "Resource Group: %s", rsc->id); if (options & pe_print_brief) { - pe__rscs_brief_output_text(out, rsc->children, options, TRUE); + pe__rscs_brief_output(out, rsc->children, options, TRUE); } else { for (GListPtr gIter = rsc->children; gIter; gIter = gIter->next) { resource_t *child_rsc = (resource_t *) gIter->data; out->message(out, crm_element_name(child_rsc->xml), options, child_rsc); } } out->end_list(out); return 0; } static int pe__ticket_html(pcmk__output_t *out, va_list args) { ticket_t *ticket = va_arg(args, 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 0; } static int pe__ticket_text(pcmk__output_t *out, va_list args) { ticket_t *ticket = va_arg(args, 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 0; } static int pe__ticket_xml(pcmk__output_t *out, va_list args) { xmlNodePtr node = NULL; ticket_t *ticket = va_arg(args, ticket_t *); node = pcmk__output_create_xml_node(out, "ticket"); xmlSetProp(node, (pcmkXmlStr) "id", (pcmkXmlStr) ticket->id); xmlSetProp(node, (pcmkXmlStr) "status", (pcmkXmlStr) (ticket->granted ? "granted" : "revoked")); xmlSetProp(node, (pcmkXmlStr) "standby", (pcmkXmlStr) (ticket->standby ? "true" : "false")); if (ticket->last_granted > -1) { xmlSetProp(node, (pcmkXmlStr) "last-granted", (pcmkXmlStr) crm_now_string(&ticket->last_granted)); } return 0; } static pcmk__message_entry_t fmt_functions[] = { { "bundle", "xml", pe__bundle_xml }, { "bundle", "html", pe__bundle_html }, { "bundle", "text", pe__bundle_text }, { "clone", "xml", pe__clone_xml }, { "clone", "html", pe__clone_html }, { "clone", "text", pe__clone_text }, { "group", "xml", pe__group_xml }, { "group", "html", pe__group_html }, { "group", "text", pe__group_text }, { "primitive", "xml", pe__resource_xml }, { "primitive", "html", pe__resource_html }, { "primitive", "text", pe__resource_text }, { "ticket", "html", pe__ticket_html }, { "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(node_t *node, gboolean details, pcmk__output_t *out) { if (node == NULL) { crm_trace(""); 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; 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) { resource_t *rsc = (resource_t *) gIter->data; pe__output_resource(LOG_TRACE, rsc, FALSE, out); } } } void pe__output_resource(int log_level, resource_t *rsc, gboolean details, pcmk__output_t *out) { long options = pe_print_log | pe_print_pending; if (rsc == NULL) { do_crm_log(log_level - 1, ""); return; } if (details) { options |= pe_print_details; } out->message(out, crm_element_name(rsc->xml), options, rsc); } diff --git a/tools/crm_mon_output.c b/tools/crm_mon_output.c index 2dbceade05..e732a60c4c 100644 --- a/tools/crm_mon_output.c +++ b/tools/crm_mon_output.c @@ -1,1109 +1,1109 @@ /* * Copyright 2019 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 #include #include #include #include #include #include #include #include #include #include #include #include "crm_mon.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; } 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) { char *time = time_t_string(last_change); char *buf = crm_strdup_printf("%s on %s '%s' (%d): call=%s, status='%s', exitreason='%s', last-rc-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, crm_element_value(xml_op, XML_RSC_OP_T_QUEUE), crm_element_value(xml_op, XML_RSC_OP_T_EXEC)); free(time); 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 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 ? " origin " : "", origin ? origin : ""); } else { return strdup(""); } } static char * op_history_string(xmlNode *xml_op, const char *task, const char *interval_ms_s, int rc, unsigned int mon_ops) { const char *call = crm_element_value(xml_op, XML_LRM_ATTR_CALLID); char *interval_str = NULL; char *buf = NULL; if (interval_ms_s && safe_str_neq(interval_ms_s, "0")) { char *pair = pcmk_format_nvpair("interval", interval_ms_s, "ms"); interval_str = crm_strdup_printf(" %s", pair); free(pair); } if (is_set(mon_ops, mon_op_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", call, task, interval_str ? interval_str : ""); } if (interval_str) { free(interval_str); } return buf; } static int 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 *); unsigned int mon_ops = va_arg(args, unsigned int); char *node_name = get_node_display_name(pe_node, mon_ops); 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 0; } static int 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 *); unsigned int mon_ops = va_arg(args, unsigned int); char *node_name = get_node_display_name(pe_node, mon_ops); 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 0; } static int ban_xml(pcmk__output_t *out, va_list args) { xmlNodePtr node = pcmk__output_create_xml_node(out, "ban"); pe_node_t *pe_node = va_arg(args, pe_node_t *); pe__location_t *location = va_arg(args, pe__location_t *); char *weight_s = crm_itoa(pe_node->weight); xmlSetProp(node, (pcmkXmlStr) "id", (pcmkXmlStr) location->id); xmlSetProp(node, (pcmkXmlStr) "resource", (pcmkXmlStr) location->rsc_lh->id); xmlSetProp(node, (pcmkXmlStr) "node", (pcmkXmlStr) pe_node->details->uname); xmlSetProp(node, (pcmkXmlStr) "weight", (pcmkXmlStr) weight_s); xmlSetProp(node, (pcmkXmlStr) "master_only", (pcmkXmlStr) (location->role_filter == RSC_ROLE_MASTER ? "true" : "false")); free(weight_s); return 0; } static int cluster_counts_html(pcmk__output_t *out, va_list args) { xmlNodePtr nodes_node = pcmk__output_create_xml_node(out, "li"); xmlNodePtr resources_node = pcmk__output_create_xml_node(out, "li"); unsigned int nnodes = va_arg(args, unsigned int); unsigned int nresources = va_arg(args, unsigned int); unsigned int ndisabled = va_arg(args, unsigned int); unsigned int nblocked = va_arg(args, unsigned int); char *nnodes_str = crm_strdup_printf("%d node%s configured", nnodes, s_if_plural(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%s configured (%d ", nresources, s_if_plural(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 starting due to failure)"); } else if (ndisabled && !nblocked) { char *s = crm_strdup_printf("%d resource%s configured (%d ", nresources, s_if_plural(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%s configured (%d ", nresources, s_if_plural(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 starting due to failure)"); } else { char *s = crm_strdup_printf("%d resource%s configured", nresources, s_if_plural(nresources)); pcmk_create_html_node(resources_node, "span", NULL, NULL, s); free(s); } return 0; } static int cluster_counts_text(pcmk__output_t *out, va_list args) { unsigned int nnodes = va_arg(args, unsigned int); unsigned int nresources = va_arg(args, unsigned int); unsigned int ndisabled = va_arg(args, unsigned int); unsigned int nblocked = va_arg(args, unsigned int); out->list_item(out, NULL, "%d node%s configured", nnodes, s_if_plural(nnodes)); if (ndisabled && nblocked) { out->list_item(out, NULL, "%d resource%s configured (%d DISABLED, %d BLOCKED from starting due to failure", nresources, s_if_plural(nresources), ndisabled, nblocked); } else if (ndisabled && !nblocked) { out->list_item(out, NULL, "%d resource%s configured (%d DISABLED)", nresources, s_if_plural(nresources), ndisabled); } else if (!ndisabled && nblocked) { out->list_item(out, NULL, "%d resource%s configured (%d BLOCKED from starting due to failure)", nresources, s_if_plural(nresources), nblocked); } else { out->list_item(out, NULL, "%d resource%s configured", nresources, s_if_plural(nresources)); } return 0; } static int cluster_counts_xml(pcmk__output_t *out, va_list args) { xmlNodePtr nodes_node = pcmk__output_create_xml_node(out, "nodes_configured"); xmlNodePtr resources_node = pcmk__output_create_xml_node(out, "resources_configured"); unsigned int nnodes = va_arg(args, unsigned int); unsigned int nresources = va_arg(args, unsigned int); unsigned int ndisabled = va_arg(args, unsigned int); unsigned int nblocked = va_arg(args, unsigned int); char *s = crm_itoa(nnodes); xmlSetProp(nodes_node, (pcmkXmlStr) "number", (pcmkXmlStr) s); free(s); s = crm_itoa(nresources); xmlSetProp(resources_node, (pcmkXmlStr) "number", (pcmkXmlStr) s); free(s); s = crm_itoa(ndisabled); xmlSetProp(resources_node, (pcmkXmlStr) "disabled", (pcmkXmlStr) s); free(s); s = crm_itoa(nblocked); xmlSetProp(resources_node, (pcmkXmlStr) "blocked", (pcmkXmlStr) s); free(s); return 0; } static int cluster_dc_html(pcmk__output_t *out, va_list args) { xmlNodePtr node = pcmk__output_create_xml_node(out, "li"); node_t *dc = va_arg(args, node_t *); const char *quorum = va_arg(args, const char *); const char *dc_version_s = va_arg(args, const char *); const char *dc_name = va_arg(args, const 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 0; } static int cluster_dc_text(pcmk__output_t *out, va_list args) { node_t *dc = va_arg(args, node_t *); const char *quorum = va_arg(args, const char *); const char *dc_version_s = va_arg(args, const char *); const char *dc_name = va_arg(args, const 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 0; } static int cluster_dc_xml(pcmk__output_t *out, va_list args) { xmlNodePtr node = pcmk__output_create_xml_node(out, "current_dc"); node_t *dc = va_arg(args, node_t *); const char *quorum = va_arg(args, const char *); const char *dc_version_s = va_arg(args, const char *); if (dc) { xmlSetProp(node, (pcmkXmlStr) "present", (pcmkXmlStr) "true"); xmlSetProp(node, (pcmkXmlStr) "version", (pcmkXmlStr) (dc_version_s ? dc_version_s : "")); xmlSetProp(node, (pcmkXmlStr) "name", (pcmkXmlStr) dc->details->uname); xmlSetProp(node, (pcmkXmlStr) "id", (pcmkXmlStr) dc->details->id); xmlSetProp(node, (pcmkXmlStr) "with_quorum", (pcmkXmlStr) (crm_is_true(quorum) ? "true" : "false")); } else { xmlSetProp(node, (pcmkXmlStr) "present", (pcmkXmlStr) "false"); } return 0; } static int cluster_options_html(pcmk__output_t *out, va_list args) { pe_working_set_t *data_set = va_arg(args, pe_working_set_t *); /* Kind of a hack - close the list started by print_cluster_summary so we * can put all the options in their own list, but just for HTML output. */ out->end_list(out); /* And then this list will be closed by print_cluster_summary since it * wants to close the list it created unconditionally. */ out->begin_list(out, NULL, NULL, "Config Options"); out->list_item(out, NULL, "STONITH of failed nodes %s", is_set(data_set->flags, pe_flag_stonith_enabled) ? "enabled" : "disabled"); out->list_item(out, NULL, "Cluster is %s", 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_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 (is_set(data_set->flags, pe_flag_maintenance_mode)) { xmlNodePtr node = pcmk__output_create_xml_node(out, "li"); 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 { out->list_item(out, NULL, "Resource management enabled"); } return 0; } static int cluster_options_text(pcmk__output_t *out, va_list args) { pe_working_set_t *data_set = va_arg(args, pe_working_set_t *); if (is_set(data_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 0; } static int cluster_options_xml(pcmk__output_t *out, va_list args) { xmlNodePtr node = pcmk__output_create_xml_node(out, "cluster_options"); pe_working_set_t *data_set = va_arg(args, pe_working_set_t *); xmlSetProp(node, (pcmkXmlStr) "stonith-enabled", (pcmkXmlStr) (is_set(data_set->flags, pe_flag_stonith_enabled) ? "true" : "false")); xmlSetProp(node, (pcmkXmlStr) "symmetric-cluster", (pcmkXmlStr) (is_set(data_set->flags, pe_flag_symmetric_cluster) ? "true" : "false")); switch (data_set->no_quorum_policy) { case no_quorum_freeze: xmlSetProp(node, (pcmkXmlStr) "no-quorum-policy", (pcmkXmlStr) "freeze"); break; case no_quorum_stop: xmlSetProp(node, (pcmkXmlStr) "no-quorum-policy", (pcmkXmlStr) "stop"); break; case no_quorum_ignore: xmlSetProp(node, (pcmkXmlStr) "no-quorum-policy", (pcmkXmlStr) "ignore"); break; case no_quorum_suicide: xmlSetProp(node, (pcmkXmlStr) "no-quorum-policy", (pcmkXmlStr) "suicide"); break; } xmlSetProp(node, (pcmkXmlStr) "maintenance-mode", (pcmkXmlStr) (is_set(data_set->flags, pe_flag_maintenance_mode) ? "true" : "false")); return 0; } static int cluster_stack_html(pcmk__output_t *out, va_list args) { xmlNodePtr node = pcmk__output_create_xml_node(out, "li"); 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 0; } static int 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 0; } static int cluster_stack_xml(pcmk__output_t *out, va_list args) { xmlNodePtr node = pcmk__output_create_xml_node(out, "stack"); const char *stack_s = va_arg(args, const char *); xmlSetProp(node, (pcmkXmlStr) "type", (pcmkXmlStr) stack_s); return 0; } static int cluster_times_html(pcmk__output_t *out, va_list args) { xmlNodePtr updated_node = pcmk__output_create_xml_node(out, "li"); xmlNodePtr changed_node = pcmk__output_create_xml_node(out, "li"); 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, crm_now_string(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 0; } static int cluster_times_xml(pcmk__output_t *out, va_list args) { xmlNodePtr updated_node = pcmk__output_create_xml_node(out, "last_update"); xmlNodePtr changed_node = pcmk__output_create_xml_node(out, "last_change"); 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 *); xmlSetProp(updated_node, (pcmkXmlStr) "time", (pcmkXmlStr) crm_now_string(NULL)); xmlSetProp(changed_node, (pcmkXmlStr) "time", (pcmkXmlStr) (last_written ? last_written : "")); xmlSetProp(changed_node, (pcmkXmlStr) "user", (pcmkXmlStr) (user ? user : "")); xmlSetProp(changed_node, (pcmkXmlStr) "client", (pcmkXmlStr) (client ? client : "")); xmlSetProp(changed_node, (pcmkXmlStr) "origin", (pcmkXmlStr) (origin ? origin : "")); return 0; } static int 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", crm_now_string(NULL)); out->list_item(out, "Last change", " %s", buf); free(buf); return 0; } static int failed_action_console(pcmk__output_t *out, va_list args) { xmlNodePtr xml_op = va_arg(args, xmlNodePtr); char *s = failed_action_string(xml_op); curses_indented_printf(out, "%s\n", s); free(s); return 0; } static int failed_action_html(pcmk__output_t *out, va_list args) { xmlNodePtr xml_op = va_arg(args, xmlNodePtr); char *s = failed_action_string(xml_op); pcmk__output_create_html_node(out, "li", NULL, NULL, s); free(s); return 0; } static int failed_action_text(pcmk__output_t *out, va_list args) { xmlNodePtr xml_op = va_arg(args, xmlNodePtr); char *s = failed_action_string(xml_op); pcmk__indented_printf(out, "%s\n", s); free(s); return 0; } static int 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"); xmlSetProp(node, (pcmkXmlStr) (op_key ? "op_key" : "id"), (pcmkXmlStr) (op_key ? op_key : "id")); xmlSetProp(node, (pcmkXmlStr) "node", (pcmkXmlStr) crm_element_value(xml_op, XML_ATTR_UNAME)); xmlSetProp(node, (pcmkXmlStr) "exitstatus", (pcmkXmlStr) services_ocf_exitcode_str(rc)); xmlSetProp(node, (pcmkXmlStr) "exitreason", (pcmkXmlStr) reason_s); xmlSetProp(node, (pcmkXmlStr) "exitcode", (pcmkXmlStr) rc_s); xmlSetProp(node, (pcmkXmlStr) "call", (pcmkXmlStr) crm_element_value(xml_op, XML_LRM_ATTR_CALLID)); xmlSetProp(node, (pcmkXmlStr) "status", (pcmkXmlStr) services_lrm_status_str(status)); if (last) { char *s = crm_itoa(crm_parse_ms(crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL_MS))); char *rc_change = time_t_string(crm_parse_int(last, "0")); xmlSetProp(node, (pcmkXmlStr) "last-rc-change", (pcmkXmlStr) rc_change); xmlSetProp(node, (pcmkXmlStr) "queued", (pcmkXmlStr) crm_element_value(xml_op, XML_RSC_OP_T_QUEUE)); xmlSetProp(node, (pcmkXmlStr) "exec", (pcmkXmlStr) crm_element_value(xml_op, XML_RSC_OP_T_EXEC)); xmlSetProp(node, (pcmkXmlStr) "interval", (pcmkXmlStr) s); xmlSetProp(node, (pcmkXmlStr) "task", (pcmkXmlStr) crm_element_value(xml_op, XML_LRM_ATTR_TASK)); free(s); free(rc_change); } free(reason_s); free(rc_s); return 0; } static int node_html(pcmk__output_t *out, va_list args) { node_t *node = va_arg(args, node_t *); unsigned int mon_ops = va_arg(args, unsigned int); gboolean full = va_arg(args, gboolean); char *node_name = get_node_display_name(node, mon_ops); char *buf = crm_strdup_printf("Node: %s", node_name); int print_opts = get_resource_display_options(mon_ops, mon_output_html); if (full) { xmlNodePtr item_node = pcmk__output_create_xml_node(out, "li"); 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 (is_set(mon_ops, mon_op_print_brief) && is_set(mon_ops, mon_op_group_by_node)) { out->begin_list(out, NULL, NULL, NULL); - pe__rscs_brief_output_html(out, node->details->running_rsc, - print_opts | pe_print_rsconly, FALSE); + pe__rscs_brief_output(out, node->details->running_rsc, print_opts | pe_print_rsconly, + FALSE); out->end_list(out); } else if (is_set(mon_ops, mon_op_group_by_node)) { GListPtr lpc2 = NULL; out->begin_list(out, NULL, NULL, NULL); for (lpc2 = node->details->running_rsc; lpc2 != NULL; lpc2 = lpc2->next) { resource_t *rsc = (resource_t *) lpc2->data; out->message(out, crm_element_name(rsc->xml), print_opts | pe_print_rsconly, rsc); } out->end_list(out); } } else { out->begin_list(out, NULL, NULL, "%s", buf); } free(buf); free(node_name); return 0; } static int node_text(pcmk__output_t *out, va_list args) { node_t *node = va_arg(args, node_t *); unsigned int mon_ops = va_arg(args, unsigned int); gboolean full = va_arg(args, gboolean); if (full) { const char *node_mode = va_arg(args, const char *); char *node_name = get_node_display_name(node, mon_ops); int print_opts = get_resource_display_options(mon_ops, mon_output_xml); 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 (is_set(mon_ops, mon_op_group_by_node)) { out->begin_list(out, NULL, NULL, "%s", buf); out->begin_list(out, NULL, NULL, "Resources"); if (is_set(mon_ops, mon_op_print_brief)) { - pe__rscs_brief_output_text(out, node->details->running_rsc, - print_opts | pe_print_rsconly, FALSE); + pe__rscs_brief_output(out, node->details->running_rsc, + print_opts | pe_print_rsconly, FALSE); } else { GListPtr gIter2 = NULL; for (gIter2 = node->details->running_rsc; gIter2 != NULL; gIter2 = gIter2->next) { resource_t *rsc = (resource_t *) gIter2->data; out->message(out, crm_element_name(rsc->xml), print_opts | pe_print_rsconly, 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", get_node_display_name(node, mon_ops)); } return 0; } static int node_xml(pcmk__output_t *out, va_list args) { node_t *node = va_arg(args, node_t *); unsigned int mon_ops __attribute__((unused)) = va_arg(args, unsigned int); gboolean full = va_arg(args, gboolean); if (full) { const char *node_type = "unknown"; int print_opts = get_resource_display_options(mon_ops, mon_output_xml); 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", node->details->online ? "true" : "false", "standby", node->details->standby ? "true" : "false", "standby_onfail", node->details->standby_onfail ? "true" : "false", "maintenance", node->details->maintenance ? "true" : "false", "pending", node->details->pending ? "true" : "false", "unclean", node->details->unclean ? "true" : "false", "shutdown", node->details->shutdown ? "true" : "false", "expected_up", node->details->expected_up ? "true" : "false", "is_dc", node->details->is_dc ? "true" : "false", "resources_running", length_s, "type", node_type); if (pe__is_guest_node(node)) { xmlNodePtr xml_node = pcmk__output_xml_peek_parent(out); xmlSetProp(xml_node, (pcmkXmlStr) "id_as_resource", (pcmkXmlStr) node->details->remote_rsc->container->id); } if (is_set(mon_ops, mon_op_group_by_node)) { GListPtr lpc = NULL; for (lpc = node->details->running_rsc; lpc != NULL; lpc = lpc->next) { resource_t *rsc = (resource_t *) lpc->data; out->message(out, crm_element_name(rsc->xml), print_opts | pe_print_rsconly, rsc); } } free(length_s); out->end_list(out); } else { xmlNodePtr parent = pcmk__output_xml_create_parent(out, "node"); xmlSetProp(parent, (pcmkXmlStr) "name", (pcmkXmlStr) node->details->uname); } return 0; } static int 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 0; } static int 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"); 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 0; } static int 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"); xmlSetProp(node, (pcmkXmlStr) "name", (pcmkXmlStr) name); xmlSetProp(node, (pcmkXmlStr) "value", (pcmkXmlStr) value); if (add_extra) { char *buf = crm_itoa(expected_score); xmlSetProp(node, (pcmkXmlStr) "expected", (pcmkXmlStr) buf); free(buf); } return 0; } static int op_history_text(pcmk__output_t *out, va_list args) { xmlNode *xml_op = va_arg(args, xmlNode *); const char *task = va_arg(args, const char *); const char *interval_ms_s = va_arg(args, const char *); int rc = va_arg(args, int); unsigned int mon_ops = va_arg(args, unsigned int); char *buf = op_history_string(xml_op, task, interval_ms_s, rc, mon_ops); out->list_item(out, NULL, "%s", buf); free(buf); return 0; } static int op_history_xml(pcmk__output_t *out, va_list args) { xmlNode *xml_op = va_arg(args, xmlNode *); const char *task = va_arg(args, const char *); const char *interval_ms_s = va_arg(args, const char *); int rc = va_arg(args, int); unsigned int mon_ops = va_arg(args, unsigned int); char *rc_s = NULL; xmlNodePtr node = pcmk__output_create_xml_node(out, "operation_history"); xmlSetProp(node, (pcmkXmlStr) "call", (pcmkXmlStr) crm_element_value(xml_op, XML_LRM_ATTR_CALLID)); xmlSetProp(node, (pcmkXmlStr) "task", (pcmkXmlStr) task); if (interval_ms_s && safe_str_neq(interval_ms_s, "0")) { char *s = crm_strdup_printf("%sms", interval_ms_s); xmlSetProp(node, (pcmkXmlStr) "interval", (pcmkXmlStr) s); free(s); } if (is_set(mon_ops, mon_op_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) { xmlSetProp(node, (pcmkXmlStr) XML_RSC_OP_LAST_CHANGE, (pcmkXmlStr) crm_now_string(&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) { xmlSetProp(node, (pcmkXmlStr) XML_RSC_OP_LAST_RUN, (pcmkXmlStr) crm_now_string(&int_value)); } } value = crm_element_value(xml_op, XML_RSC_OP_T_EXEC); if (value) { char *s = crm_strdup_printf("%sms", value); xmlSetProp(node, (pcmkXmlStr) XML_RSC_OP_T_EXEC, (pcmkXmlStr) s); free(s); } value = crm_element_value(xml_op, XML_RSC_OP_T_QUEUE); if (value) { char *s = crm_strdup_printf("%sms", value); xmlSetProp(node, (pcmkXmlStr) XML_RSC_OP_T_QUEUE, (pcmkXmlStr) s); free(s); } } rc_s = crm_itoa(rc); xmlSetProp(node, (pcmkXmlStr) "rc", (pcmkXmlStr) rc_s); xmlSetProp(node, (pcmkXmlStr) "rc_text", (pcmkXmlStr) services_ocf_exitcode_str(rc)); free(rc_s); return 0; } static int stonith_event_console(pcmk__output_t *out, va_list args) { stonith_history_t *event = va_arg(args, stonith_history_t *); int full_history = va_arg(args, int); gboolean later_succeeded = va_arg(args, gboolean); char *buf = NULL; buf = time_t_string(event->completed); switch (event->state) { case st_failed: curses_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: curses_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: curses_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 0; } static int ticket_console(pcmk__output_t *out, va_list args) { ticket_t *ticket = va_arg(args, 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 0; } static pcmk__message_entry_t fmt_functions[] = { { "ban", "console", ban_text }, { "ban", "html", ban_html }, { "ban", "text", ban_text }, { "ban", "xml", ban_xml }, { "bundle", "console", pe__bundle_text }, { "cluster-counts", "console", cluster_counts_text }, { "cluster-counts", "html", cluster_counts_html }, { "cluster-counts", "text", cluster_counts_text }, { "cluster-counts", "xml", cluster_counts_xml }, { "cluster-dc", "console", cluster_dc_text }, { "cluster-dc", "html", cluster_dc_html }, { "cluster-dc", "text", cluster_dc_text }, { "cluster-dc", "xml", cluster_dc_xml }, { "cluster-options", "console", cluster_options_text }, { "cluster-options", "html", cluster_options_html }, { "cluster-options", "text", cluster_options_text }, { "cluster-options", "xml", cluster_options_xml }, { "cluster-stack", "console", cluster_stack_text }, { "cluster-stack", "html", cluster_stack_html }, { "cluster-stack", "text", cluster_stack_text }, { "cluster-stack", "xml", cluster_stack_xml }, { "cluster-times", "console", cluster_times_text }, { "cluster-times", "html", cluster_times_html }, { "cluster-times", "text", cluster_times_text }, { "cluster-times", "xml", cluster_times_xml }, { "failed-action", "console", failed_action_console }, { "failed-action", "html", failed_action_html }, { "failed-action", "text", failed_action_text }, { "failed-action", "xml", failed_action_xml }, { "node", "console", node_text }, { "node", "html", node_html }, { "node", "text", node_text }, { "node", "xml", node_xml }, { "node-attribute", "console", node_attribute_text }, { "node-attribute", "html", node_attribute_html }, { "node-attribute", "text", node_attribute_text }, { "node-attribute", "xml", node_attribute_xml }, { "op-history", "console", op_history_text }, { "op-history", "html", op_history_text }, { "op-history", "text", op_history_text }, { "op-history", "xml", op_history_xml }, { "primitive", "console", pe__resource_text }, { "stonith-event", "console", stonith_event_console }, { "ticket", "console", ticket_console }, { NULL, NULL, NULL } }; void crm_mon_register_messages(pcmk__output_t *out) { pcmk__register_messages(out, fmt_functions); }