23#ifdef PCMK__COMPAT_2_0
24#define PROMOTED_INSTANCES PCMK__ROLE_PROMOTED_LEGACY "s"
25#define UNPROMOTED_INSTANCES PCMK__ROLE_UNPROMOTED_LEGACY "s"
27#define PROMOTED_INSTANCES PCMK__ROLE_PROMOTED
28#define UNPROMOTED_INSTANCES PCMK__ROLE_UNPROMOTED
31typedef struct clone_variant_data_s {
36 int promoted_node_max;
47 xmlNode *xml_obj_child;
50#define get_clone_variant_data(data, rsc) \
51 CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_clone)); \
52 data = (clone_variant_data_t *) rsc->variant_opaque;
68 return clone_data->clone_max;
85 return clone_data->clone_node_max;
102 return clone_data->promoted_max;
119 return clone_data->promoted_node_max;
123sorted_hash_table_values(GHashTable *table)
125 GList *retval = NULL;
129 g_hash_table_iter_init(&iter, table);
130 while (g_hash_table_iter_next(&iter, &key, &value)) {
131 if (!g_list_find_custom(retval, value, (GCompareFunc) strcmp)) {
132 retval = g_list_prepend(retval, (
char *) value);
136 retval = g_list_sort(retval, (GCompareFunc) strcmp);
141nodes_with_status(GHashTable *table,
const char *status)
143 GList *retval = NULL;
147 g_hash_table_iter_init(&iter, table);
148 while (g_hash_table_iter_next(&iter, &key, &value)) {
149 if (!strcmp((
char *) value, status)) {
150 retval = g_list_prepend(retval, key);
159node_list_to_str(
const GList *list)
161 GString *retval = NULL;
163 for (
const GList *iter = list; iter != NULL; iter = iter->next) {
164 pcmk__add_word(&retval, 1024, (
const char *) iter->data);
174 GString *attrs = NULL;
197 rsc->
id,
ID(clone_data->xml_obj_child),
198 (
const char *) attrs->str, desc ?
" (" :
"",
199 desc ? desc :
"", desc ?
")" :
"");
200 g_string_free(attrs, TRUE);
203 rsc->
id,
ID(clone_data->xml_obj_child),
204 desc ?
" (" :
"", desc ? desc :
"",
213 if (pe_rsc_is_clone(rsc)) {
217 "such as %s can be used only as anonymous clones",
218 rsc->
id, standard, rid);
220 clone_data->clone_node_max = 1;
221 clone_data->clone_max = QB_MIN(clone_data->clone_max,
229 char *child_id = NULL;
231 const char *child_base = NULL;
236 child_base =
ID(clone_data->xml_obj_child);
247 gboolean as_orphan = FALSE;
248 char *inc_num = NULL;
249 char *inc_max = NULL;
251 xmlNode *child_copy = NULL;
256 CRM_CHECK(clone_data->xml_obj_child != NULL,
return FALSE);
258 if (clone_data->total_clones >= clone_data->clone_max) {
264 inc_num = pcmk__itoa(clone_data->total_clones);
265 inc_max = pcmk__itoa(clone_data->clone_max);
267 child_copy =
copy_xml(clone_data->xml_obj_child);
278 clone_data->total_clones += 1;
279 pe_rsc_trace(child_rsc,
"Setting clone attributes for: %s", child_rsc->
id);
310 const char *deprecated_name,
int default_value)
312 int integer = default_value;
313 const char *value = g_hash_table_lookup(rsc->
meta, meta_name);
315 if ((value == NULL) && (deprecated_name != NULL)) {
316 value = g_hash_table_lookup(rsc->
meta, deprecated_name);
328 xmlNode *a_child = NULL;
329 xmlNode *xml_obj = rsc->
xml;
346 clone_data->promoted_node_max =
365 clone_data->flags = pcmk__set_flags_as(__func__, __LINE__,
LOG_TRACE,
369 "pcmk__clone_ordered");
373 && (clone_data->clone_node_max > 1)) {
376 "because anonymous clones support only one instance "
377 "per node", clone_data->clone_node_max, rsc->
id);
378 clone_data->clone_node_max = 1;
382 pe_rsc_trace(rsc,
"\tClone max: %d", clone_data->clone_max);
383 pe_rsc_trace(rsc,
"\tClone node max: %d", clone_data->clone_node_max);
390 for (a_child = pcmk__xe_first_child(xml_obj); a_child != NULL;
391 a_child = pcmk__xe_next(a_child)) {
394 clone_data->xml_obj_child = a_child;
399 if (clone_data->xml_obj_child == NULL) {
420 if (clone_data->clone_max <= 0) {
430 for (lpc = 0; lpc < clone_data->clone_max; lpc++) {
437 pe_rsc_trace(rsc,
"Added %d children to resource %s...", clone_data->clone_max, rsc->
id);
446 for (; gIter != NULL; gIter = gIter->next) {
448 gboolean child_active = child_rsc->
fns->
active(child_rsc, all);
450 if (all == FALSE && child_active) {
452 }
else if (all && child_active == FALSE) {
469short_print(
const char *list,
const char *prefix,
const char *
type,
470 const char *suffix,
long options,
void *print_data)
476 if (!pcmk__str_empty(list)) {
497 const char *target_role = g_hash_table_lookup(rsc->
meta,
503 target_role = g_hash_table_lookup(instance->
meta,
512 const char *target_role = configured_role_str(rsc);
525clone_print_xml(
pcmk_resource_t *rsc,
const char *pre_text,
long options,
529 const char *target_role = configured_role_str(rsc);
547 for (; gIter != NULL; gIter = gIter->next) {
550 child_rsc->fns->print(child_rsc, child_text, options, print_data);
571 for (gIter = rsc->
children; gIter != NULL; gIter = gIter->next) {
596 GString *list_text = NULL;
597 char *child_text = NULL;
598 GString *stopped_list = NULL;
600 GList *promoted_list = NULL;
601 GList *started_list = NULL;
605 int active_instances = 0;
607 if (pre_text == NULL) {
612 clone_print_xml(rsc, pre_text, options, print_data);
621 pre_text ? pre_text :
"", rsc->
id,
ID(clone_data->xml_obj_child),
633 for (; gIter != NULL; gIter = gIter->next) {
634 gboolean print_full = FALSE;
636 gboolean partially_active = child_rsc->
fns->
active(child_rsc, FALSE);
657 }
else if (partially_active == FALSE) {
662 pcmk__add_word(&stopped_list, 1024, child_rsc->
id);
672 }
else if (child_rsc->
fns->
active(child_rsc, TRUE)) {
677 location = child_rsc->
fns->
location(child_rsc, NULL, TRUE);
687 promoted_list = g_list_append(promoted_list, location);
690 started_list = g_list_append(started_list, location);
707 child_rsc->
fns->
print(child_rsc, child_text, options, print_data);
716 for (gIter = promoted_list; gIter; gIter = gIter->next) {
719 pcmk__add_word(&list_text, 1024,
host->details->uname);
723 if (list_text != NULL) {
724 short_print((
const char *) list_text->str, child_text,
726 g_string_truncate(list_text, 0);
728 g_list_free(promoted_list);
732 for (gIter = started_list; gIter; gIter = gIter->next) {
735 pcmk__add_word(&list_text, 1024,
host->details->uname);
739 if (list_text != NULL) {
744 short_print((
const char *) list_text->str, child_text,
746 options, print_data);
748 short_print((
const char *) list_text->str, child_text,
753 short_print((
const char *) list_text->str, child_text,
"Started",
754 NULL, options, print_data);
758 g_list_free(started_list);
761 const char *state =
"Stopped";
765 state =
"Stopped (disabled)";
769 && (clone_data->clone_max > active_instances)) {
775 if (stopped_list != NULL) {
776 g_string_truncate(stopped_list, 0);
783 list = g_hash_table_get_values(rsc->
known_on);
787 for (nIter = list; nIter != NULL; nIter = nIter->next) {
791 pcmk__add_word(&stopped_list, 1024, node->
details->
uname);
797 if (stopped_list != NULL) {
798 short_print((
const char *) stopped_list->str, child_text, state,
799 NULL, options, print_data);
807 if (list_text != NULL) {
808 g_string_free(list_text, TRUE);
811 if (stopped_list != NULL) {
812 g_string_free(stopped_list, TRUE);
822 uint32_t show_opts = va_arg(args, uint32_t);
824 GList *only_node = va_arg(args, GList *);
825 GList *only_rsc = va_arg(args, GList *);
828 const char *desc = NULL;
832 gboolean printed_header = FALSE;
833 gboolean print_everything = TRUE;
844 all = g_list_prepend(all, (gpointer)
"*");
846 for (; gIter != NULL; gIter = gIter->next) {
853 if (child_rsc->
fns->
is_filtered(child_rsc, only_rsc, print_everything)) {
857 if (!printed_header) {
858 printed_header = TRUE;
873 "target_role", configured_role_str(rsc),
874 "description", desc);
878 out->message(out, crm_map_element_name(child_rsc->
xml), show_opts,
879 child_rsc, only_node, all);
882 if (printed_header) {
895 uint32_t show_opts = va_arg(args, uint32_t);
897 GList *only_node = va_arg(args, GList *);
898 GList *only_rsc = va_arg(args, GList *);
900 GHashTable *stopped = NULL;
902 GString *list_text = NULL;
904 GList *promoted_list = NULL;
905 GList *started_list = NULL;
908 const char *desc = NULL;
911 int active_instances = 0;
913 gboolean print_everything = TRUE;
926 for (; gIter != NULL; gIter = gIter->next) {
927 gboolean print_full = FALSE;
929 gboolean partially_active = child_rsc->fns->active(child_rsc, FALSE);
935 if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
953 && (child_rsc->pending_task != NULL)
954 && strcmp(child_rsc->pending_task,
"probe")) {
958 }
else if (partially_active == FALSE) {
963 if (stopped == NULL) {
966 g_hash_table_insert(stopped, strdup(child_rsc->id), strdup(
"Stopped"));
976 }
else if (child_rsc->fns->active(child_rsc, TRUE)) {
981 location = child_rsc->fns->location(child_rsc, NULL, TRUE);
985 enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
991 promoted_list = g_list_append(promoted_list, location);
994 started_list = g_list_append(started_list, location);
1010 clone_header(out, &rc, rsc, clone_data, desc);
1013 all = g_list_prepend(all, (gpointer)
"*");
1014 out->message(out, crm_map_element_name(child_rsc->xml), show_opts,
1015 child_rsc, only_node, all);
1027 for (gIter = promoted_list; gIter; gIter = gIter->next) {
1035 pcmk__add_word(&list_text, 1024,
host->details->uname);
1038 g_list_free(promoted_list);
1040 if ((list_text != NULL) && (list_text->len > 0)) {
1041 clone_header(out, &rc, rsc, clone_data, desc);
1044 (
const char *) list_text->str);
1045 g_string_truncate(list_text, 0);
1050 for (gIter = started_list; gIter; gIter = gIter->next) {
1058 pcmk__add_word(&list_text, 1024,
host->details->uname);
1061 g_list_free(started_list);
1063 if ((list_text != NULL) && (list_text->len > 0)) {
1064 clone_header(out, &rc, rsc, clone_data, desc);
1070 out->list_item(out, NULL,
1072 (
const char *) list_text->str);
1075 (
const char *) list_text->str);
1079 out->list_item(out, NULL,
"Started: [ %s ]",
1080 (
const char *) list_text->str);
1084 if (list_text != NULL) {
1085 g_string_free(list_text, TRUE);
1090 && (clone_data->clone_max > active_instances)) {
1096 if (stopped != NULL) {
1097 g_hash_table_destroy(stopped);
1105 list = g_hash_table_get_values(rsc->
known_on);
1109 for (nIter = list; nIter != NULL; nIter = nIter->next) {
1116 const char *state =
"Stopped";
1119 state =
"Stopped (disabled)";
1122 if (stopped == NULL) {
1125 if (probe_op != NULL) {
1129 g_hash_table_insert(stopped, strdup(node->details->uname),
1132 g_hash_table_insert(stopped, strdup(node->details->uname),
1140 if (stopped != NULL) {
1141 GList *list = sorted_hash_table_values(stopped);
1143 clone_header(out, &rc, rsc, clone_data, desc);
1145 for (GList *status_iter = list; status_iter != NULL; status_iter = status_iter->next) {
1146 const char *status = status_iter->data;
1147 GList *nodes = nodes_with_status(stopped, status);
1148 GString *nodes_str = node_list_to_str(nodes);
1150 if (nodes_str != NULL) {
1151 if (nodes_str->len > 0) {
1152 out->list_item(out, NULL,
"%s: [ %s ]", status,
1153 (
const char *) nodes_str->str);
1155 g_string_free(nodes_str, TRUE);
1162 g_hash_table_destroy(stopped);
1168 }
else if (active_instances == 0) {
1169 clone_header(out, &rc, rsc, clone_data, desc);
1188 for (GList *gIter = rsc->
children; gIter != NULL; gIter = gIter->next) {
1194 child_rsc->
xml = NULL;
1198 child_rsc->
fns->
free(child_rsc);
1204 CRM_ASSERT(clone_data->demote_notify == NULL);
1206 CRM_ASSERT(clone_data->start_notify == NULL);
1207 CRM_ASSERT(clone_data->promote_notify == NULL);
1219 for (; gIter != NULL; gIter = gIter->next) {
1223 if (a_role > clone_role) {
1224 clone_role = a_role;
1243 if (pe_rsc_is_clone(rsc)) {
1255 gboolean check_parent)
1257 gboolean passes = FALSE;
1267 for (
const GList *iter = rsc->
children;
1268 iter != NULL; iter = iter->next) {
1288 return ID(clone_data->xml_obj_child);
1327 clone_data->flags = pcmk__set_flags_as(__func__, __LINE__,
LOG_TRACE,
1329 clone_data->flags, flag,
"flag");
1350 return pcmk_all_flags_set(clone_data->flags,
flags);
1373 !any_promoting,
true);
1377 !any_promoting,
true);
1381 if (clone_data->promote_notify == NULL) {
1390 !any_demoting,
true);
1394 !any_demoting,
true);
1398 if (clone_data->demote_notify == NULL) {
1404 if (clone_data->promote_notify != NULL) {
1452 clone_data->demote_notify = NULL;
1455 clone_data->stop_notify = NULL;
1458 clone_data->start_notify = NULL;
1461 clone_data->promote_notify = NULL;
1483 if (clone_data->start_notify == NULL) {
1489 if (clone_data->stop_notify == NULL) {
1493 if ((clone_data->start_notify != NULL)
1494 && (clone_data->stop_notify != NULL)) {
1515 return clone_data->clone_node_max;
@ pcmk__ar_ordered
Actions are ordered (optionally, if no other flags are set)
#define PCMK_ACTION_PROMOTED
#define PCMK_ACTION_PROMOTE
#define PCMK_ACTION_START
#define PCMK_ACTION_DEMOTED
#define PCMK_ACTION_DEMOTE
bool is_set_recursive(const pcmk_resource_t *rsc, long long flag, bool any)
void pe__create_promotable_pseudo_ops(pcmk_resource_t *clone, bool any_promoting, bool any_demoting)
void pe__create_clone_notifications(pcmk_resource_t *clone)
enum rsc_role_e clone_resource_state(const pcmk_resource_t *rsc, gboolean current)
int pe__clone_promoted_node_max(const pcmk_resource_t *clone)
int pe__clone_max(const pcmk_resource_t *clone)
#define get_clone_variant_data(data, rsc)
pcmk_resource_t * pe__create_clone_child(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler)
bool pe__is_universal_clone(const pcmk_resource_t *rsc, const pcmk_scheduler_t *scheduler)
pcmk_resource_t * find_clone_instance(const pcmk_resource_t *rsc, const char *sub_id)
gboolean clone_unpack(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler)
void clone_free(pcmk_resource_t *rsc)
void pe__create_clone_notif_pseudo_ops(pcmk_resource_t *clone, pcmk_action_t *start, pcmk_action_t *started, pcmk_action_t *stop, pcmk_action_t *stopped)
void clone_print(pcmk_resource_t *rsc, const char *pre_text, long options, void *print_data)
struct clone_variant_data_s clone_variant_data_t
void pe__force_anon(const char *standard, pcmk_resource_t *rsc, const char *rid, pcmk_scheduler_t *scheduler)
bool pe__clone_flag_is_set(const pcmk_resource_t *clone, uint32_t flags)
bool pe__clone_is_ordered(const pcmk_resource_t *clone)
gboolean clone_active(pcmk_resource_t *rsc, gboolean all)
unsigned int pe__clone_max_per_node(const pcmk_resource_t *rsc)
int pe__set_clone_flag(pcmk_resource_t *clone, enum pcmk__clone_flags flag)
int pe__clone_node_max(const pcmk_resource_t *clone)
int pe__clone_promoted_max(const pcmk_resource_t *clone)
#define PROMOTED_INSTANCES
const char * pe__clone_child_id(const pcmk_resource_t *rsc)
void pe__free_clone_notification_data(pcmk_resource_t *clone)
gboolean pe__clone_is_filtered(const pcmk_resource_t *rsc, GList *only_rsc, gboolean check_parent)
#define UNPROMOTED_INSTANCES
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
gboolean crm_is_true(const char *s)
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
const char * role2text(enum rsc_role_e role)
enum rsc_role_e text2role(const char *role)
int pe__unpack_resource(xmlNode *xml_obj, pcmk_resource_t **rsc, pcmk_resource_t *parent, pcmk_scheduler_t *scheduler)
enum crm_ais_msg_types type
#define CRM_CHECK(expr, failure_action)
#define pcmk__config_err(fmt...)
#define XML_RSC_ATTR_TARGET_ROLE
#define PCMK_META_CLONE_NODE_MAX
#define XML_RSC_ATTR_STICKINESS
#define PCMK_META_PROMOTED_MAX
#define XML_RSC_ATTR_INCARNATION
#define PCMK_META_CLONE_MAX
#define PCMK_XA_PROMOTED_NODE_MAX_LEGACY
#define XML_CIB_TAG_GROUP
#define XML_RSC_ATTR_ORDERED
#define XML_RSC_ATTR_UNIQUE
#define XML_CIB_TAG_RESOURCE
#define PCMK_META_PROMOTED_NODE_MAX
#define PCMK_XA_PROMOTED_MAX_LEGACY
pcmk_scheduler_t * scheduler
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Control output from tools.
@ pcmk_show_inactive_rscs
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
#define PCMK__OUTPUT_LIST_HEADER(out_obj, cond, retcode, title...)
#define PCMK__OUTPUT_ARGS(ARGS...)
#define PCMK__OUTPUT_LIST_FOOTER(out_obj, retcode)
void pe__free_action_notification_data(notify_data_t *n_data)
notify_data_t * pe__action_notif_pseudo_ops(pcmk_resource_t *rsc, const char *task, pcmk_action_t *action, pcmk_action_t *complete)
void pe__create_action_notifications(pcmk_resource_t *rsc, notify_data_t *n_data)
#define status_print(fmt, args...)
int pe__clone_xml(pcmk__output_t *out, va_list args)
int pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name, size_t pairs_count,...)
const char * pe__resource_description(const pcmk_resource_t *rsc, uint32_t show_opts)
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
gboolean order_actions(pcmk_action_t *lh_action, pcmk_action_t *rh_action, uint32_t flags)
void pe__set_resource_flags_recursive(pcmk_resource_t *rsc, uint64_t flags)
pcmk_action_t * pe__new_rsc_pseudo_action(pcmk_resource_t *rsc, const char *task, bool optional, bool runnable)
int pe__clone_default(pcmk__output_t *out, va_list args)
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
#define pe_rsc_trace(rsc, fmt, args...)
xmlNode * pe__failed_probe_for_rsc(const pcmk_resource_t *rsc, const char *name)
void common_free(pcmk_resource_t *rsc)
bool pe__resource_is_disabled(const pcmk_resource_t *rsc)
bool pcmk__rsc_filtered_by_node(pcmk_resource_t *rsc, GList *only_node)
void add_hash_param(GHashTable *hash, const char *name, const char *value)
@ pcmk_rsc_promotable
Whether resource can be promoted and demoted.
@ pcmk_rsc_unique
Whether resource is not an anonymous clone instance.
@ pcmk_rsc_maintenance
Whether resource, its node, or entire cluster is in maintenance mode.
@ pcmk_rsc_removed
Whether resource has been removed from the configuration.
@ pcmk_rsc_managed
Whether resource is managed.
@ pcmk_rsc_ignore_failure
Whether resource has an ignorable failure.
@ pcmk_rsc_failed
Whether resource is considered failed.
@ pcmk_role_unknown
Resource role is unknown.
@ pcmk_role_unpromoted
Unpromoted.
@ pcmk_role_stopped
Stopped.
Cluster status and scheduling.
pcmk_resource_t * pe_find_resource(GList *rsc_list, const char *id_rh)
pcmk_node_t * pe_find_node(const GList *node_list, const char *node_name)
Find a node by name in a list of nodes.
const char * rsc_printable_id(const pcmk_resource_t *rsc)
int pcmk__numeric_strcasecmp(const char *s1, const char *s2)
int pcmk__scan_min_int(const char *text, int *result, int minimum)
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
This structure contains everything that makes up a single output formatter.
Implementation of pcmk_action_t.
Implementation of pcmk_node_t.
struct pe_node_shared_s * details
Basic node information.
gboolean online
Whether online.
const char * uname
Node name in cluster.
gboolean unclean
Whether node requires fencing.
Implementation of pcmk_resource_t.
GList * running_on
Nodes where resource may be active.
GHashTable * meta
Resource's meta-attributes.
GList * children
Resource's child resources, if any.
pcmk_rsc_methods_t * fns
Resource object methods.
GHashTable * known_on
Nodes where resource has been probed (key is node ID, not name)
char * id
Resource ID in configuration.
xmlNode * xml
Resource configuration (possibly expanded from template)
GHashTable * allowed_nodes
Nodes where resource may run (key is node ID, not name)
void * variant_opaque
Variant-specific (and private) data.
unsigned long long flags
Group of enum pcmk_rsc_flags.
char * pending_task
Pending action in history, if any.
xmlNode * orig_xml
Original resource configuration, if using template.
Implementation of pcmk_scheduler_t.
GList * nodes
Nodes in cluster.
void(* free)(pcmk_resource_t *rsc)
Free all memory used by a resource.
void(* print)(pcmk_resource_t *rsc, const char *pre_text, long options, void *print_data)
enum rsc_role_e(* state)(const pcmk_resource_t *rsc, gboolean current)
Get resource's current or assigned role.
pcmk_node_t *(* location)(const pcmk_resource_t *rsc, GList **list, int current)
List nodes where a resource (or any of its children) is.
gboolean(* is_filtered)(const pcmk_resource_t *rsc, GList *only_rsc, gboolean check_parent)
Check whether a given resource is in a list of resources.
gboolean(* active)(pcmk_resource_t *rsc, gboolean all)
Check whether a resource is active.
void free_xml(xmlNode *child)
xmlNode * copy_xml(xmlNode *src_node)