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 31 typedef 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;
123 sorted_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);
141 nodes_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);
159 node_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) {
469 short_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);
525 clone_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)) {
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);
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;
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
bool pe__clone_is_ordered(const pcmk_resource_t *clone)
#define CRM_CHECK(expr, failure_action)
#define PCMK_XA_PROMOTED_MAX_LEGACY
xmlNode * orig_xml
Original resource configuration, if using template.
GHashTable * known_on
Nodes where resource has been probed (key is node ID, not name)
unsigned int pe__clone_max_per_node(const pcmk_resource_t *rsc)
#define PROMOTED_INSTANCES
pcmk_node_t *(* location)(const pcmk_resource_t *rsc, GList **list, int current)
List nodes where a resource (or any of its children) is.
Control output from tools.
int pcmk__scan_min_int(const char *text, int *result, int minimum)
bool is_set_recursive(const pcmk_resource_t *rsc, long long flag, bool any)
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
xmlNode * pe__failed_probe_for_rsc(const pcmk_resource_t *rsc, const char *name)
bool pe__is_universal_clone(const pcmk_resource_t *rsc, const pcmk_scheduler_t *scheduler)
void pe__create_clone_notifications(pcmk_resource_t *clone)
GList * children
Resource's child resources, if any.
#define UNPROMOTED_INSTANCES
gboolean order_actions(pcmk_action_t *lh_action, pcmk_action_t *rh_action, uint32_t flags)
void pe__force_anon(const char *standard, pcmk_resource_t *rsc, const char *rid, pcmk_scheduler_t *scheduler)
xmlNode * xml
Resource configuration (possibly expanded from template)
enum rsc_role_e(* state)(const pcmk_resource_t *rsc, gboolean current)
Get resource's current or assigned role.
pcmk_resource_t * pe__create_clone_child(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler)
#define XML_RSC_ATTR_INCARNATION
gboolean clone_active(pcmk_resource_t *rsc, gboolean all)
Implementation of pcmk_action_t.
#define pcmk__config_err(fmt...)
const char * pe__resource_description(const pcmk_resource_t *rsc, uint32_t show_opts)
GHashTable * meta
Resource's meta-attributes.
Whether resource, its node, or entire cluster is in maintenance mode.
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
int pe__clone_default(pcmk__output_t *out, va_list args)
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
#define XML_RSC_ATTR_STICKINESS
enum crm_ais_msg_types type
const char * rsc_printable_id(const pcmk_resource_t *rsc)
void pe__set_resource_flags_recursive(pcmk_resource_t *rsc, uint64_t flags)
void(* print)(pcmk_resource_t *rsc, const char *pre_text, long options, void *print_data)
void clone_free(pcmk_resource_t *rsc)
struct clone_variant_data_s clone_variant_data_t
gboolean clone_unpack(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler)
Implementation of pcmk_scheduler_t.
char * pending_task
Pending action in history, if any.
int pe__unpack_resource(xmlNode *xml_obj, pcmk_resource_t **rsc, pcmk_resource_t *parent, pcmk_scheduler_t *scheduler)
#define PCMK_XA_PROMOTED_NODE_MAX_LEGACY
GList * nodes
Nodes in cluster.
void clone_print(pcmk_resource_t *rsc, const char *pre_text, long options, void *print_data)
xmlNode * copy_xml(xmlNode *src_node)
const char * role2text(enum rsc_role_e role)
pcmk_action_t * pe__new_rsc_pseudo_action(pcmk_resource_t *rsc, const char *task, bool optional, bool runnable)
int pe__clone_promoted_max(const pcmk_resource_t *clone)
#define PCMK_ACTION_DEMOTE
pcmk_resource_t * pe_find_resource(GList *rsc_list, const char *id_rh)
void common_free(pcmk_resource_t *rsc)
void(* free)(pcmk_resource_t *rsc)
Free all memory used by a resource.
void pe__free_action_notification_data(notify_data_t *n_data)
Implementation of pcmk_resource_t.
Actions are ordered (optionally, if no other flags are set)
#define PCMK_META_CLONE_MAX
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
#define XML_CIB_TAG_RESOURCE
void pe__create_promotable_pseudo_ops(pcmk_resource_t *clone, bool any_promoting, bool any_demoting)
int pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name, size_t pairs_count,...)
Whether resource is considered failed.
int pe__clone_xml(pcmk__output_t *out, va_list args)
pcmk_node_t * pe_find_node(const GList *node_list, const char *node_name)
Find a node by name in a list of nodes.
void pe__create_action_notifications(pcmk_resource_t *rsc, notify_data_t *n_data)
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
struct pe_node_shared_s * details
Basic node information.
#define PCMK_ACTION_START
unsigned long long flags
Group of enum pcmk_rsc_flags.
const char * uname
Node name in cluster.
#define XML_RSC_ATTR_ORDERED
PCMK__OUTPUT_ARGS("clone", "uint32_t", "pcmk_resource_t *", "GList *", "GList *")
#define XML_RSC_ATTR_TARGET_ROLE
#define PCMK_META_PROMOTED_MAX
void free_xml(xmlNode *child)
#define get_clone_variant_data(data, rsc)
Implementation of pcmk_node_t.
enum rsc_role_e text2role(const char *role)
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
#define PCMK_META_PROMOTED_NODE_MAX
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
pcmk_resource_t * find_clone_instance(const pcmk_resource_t *rsc, const char *sub_id)
enum rsc_role_e clone_resource_state(const pcmk_resource_t *rsc, gboolean current)
#define XML_RSC_ATTR_UNIQUE
void pe__free_clone_notification_data(pcmk_resource_t *clone)
#define PCMK__OUTPUT_LIST_FOOTER(out_obj, retcode)
Whether resource has an ignorable failure.
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_clone_notif_pseudo_ops(pcmk_resource_t *clone, pcmk_action_t *start, pcmk_action_t *started, pcmk_action_t *stop, pcmk_action_t *stopped)
gboolean(* active)(pcmk_resource_t *rsc, gboolean all)
Check whether a resource is active.
int pe__clone_node_max(const pcmk_resource_t *clone)
#define PCMK__OUTPUT_LIST_HEADER(out_obj, cond, retcode, title...)
Cluster status and scheduling.
int pe__clone_max(const pcmk_resource_t *clone)
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
void add_hash_param(GHashTable *hash, const char *name, const char *value)
int pe__set_clone_flag(pcmk_resource_t *clone, enum pcmk__clone_flags flag)
pcmk_rsc_methods_t * fns
Resource object methods.
void * variant_opaque
Variant-specific (and private) data.
pcmk_scheduler_t * scheduler
const char * pe__clone_child_id(const pcmk_resource_t *rsc)
#define status_print(fmt, args...)
bool pcmk__rsc_filtered_by_node(pcmk_resource_t *rsc, GList *only_node)
This structure contains everything that makes up a single output formatter.
bool pe__resource_is_disabled(const pcmk_resource_t *rsc)
#define PCMK_ACTION_PROMOTE
int pcmk__numeric_strcasecmp(const char *s1, const char *s2)
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.
GList * running_on
Nodes where resource may be active.
bool pe__clone_flag_is_set(const pcmk_resource_t *clone, uint32_t flags)
gboolean pe__clone_is_filtered(const pcmk_resource_t *rsc, GList *only_rsc, gboolean check_parent)
#define PCMK_ACTION_PROMOTED
#define PCMK_META_CLONE_NODE_MAX
gboolean crm_is_true(const char *s)
int pe__clone_promoted_node_max(const pcmk_resource_t *clone)
Whether resource can be promoted and demoted.
#define XML_CIB_TAG_GROUP
Resource role is unknown.
#define pe_rsc_trace(rsc, fmt, args...)
#define PCMK_ACTION_DEMOTED
Whether resource is managed.
gboolean unclean
Whether node requires fencing.
Whether resource has been removed from the configuration.
gboolean online
Whether online.
Whether resource is not an anonymous clone instance.
char * id
Resource ID in configuration.
GHashTable * allowed_nodes
Nodes where resource may run (key is node ID, not name)
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)