19 #define VARIANT_CLONE 1 
   22 #ifdef PCMK__COMPAT_2_0 
   23 #define PROMOTED_INSTANCES   RSC_ROLE_PROMOTED_LEGACY_S "s" 
   24 #define UNPROMOTED_INSTANCES RSC_ROLE_UNPROMOTED_LEGACY_S "s" 
   26 #define PROMOTED_INSTANCES   RSC_ROLE_PROMOTED_S 
   27 #define UNPROMOTED_INSTANCES RSC_ROLE_UNPROMOTED_S 
   34     if (pe_rsc_is_clone(rsc)) {
 
   35         clone_variant_data_t *clone_data = NULL;
 
   37         get_clone_variant_data(clone_data, rsc);
 
   40                 "such as %s can be used only as anonymous clones",
 
   41                 rsc->
id, standard, rid);
 
   43         clone_data->clone_node_max = 1;
 
   44         clone_data->clone_max = QB_MIN(clone_data->clone_max,
 
   45                                        g_list_length(data_set->
nodes));
 
   52     char *child_id = NULL;
 
   54     const char *child_base = NULL;
 
   55     clone_variant_data_t *clone_data = NULL;
 
   57     get_clone_variant_data(clone_data, rsc);
 
   59     child_base = 
ID(clone_data->xml_obj_child);
 
   70     gboolean as_orphan = FALSE;
 
   74     xmlNode *child_copy = NULL;
 
   75     clone_variant_data_t *clone_data = NULL;
 
   77     get_clone_variant_data(clone_data, rsc);
 
   79     CRM_CHECK(clone_data->xml_obj_child != NULL, 
return FALSE);
 
   81     if (clone_data->total_clones >= clone_data->clone_max) {
 
   87     inc_num = pcmk__itoa(clone_data->total_clones);
 
   88     inc_max = pcmk__itoa(clone_data->clone_max);
 
   90     child_copy = 
copy_xml(clone_data->xml_obj_child);
 
   94     if (
common_unpack(child_copy, &child_rsc, rsc, data_set) == FALSE) {
 
  102     clone_data->total_clones += 1;
 
  103     pe_rsc_trace(child_rsc, 
"Setting clone attributes for: %s", child_rsc->
id);
 
  123     xmlNode *a_child = NULL;
 
  124     xmlNode *xml_obj = rsc->
xml;
 
  125     clone_variant_data_t *clone_data = NULL;
 
  133     clone_data = calloc(1, 
sizeof(clone_variant_data_t));
 
  137         const char *promoted_max = NULL;
 
  138         const char *promoted_node_max = NULL;
 
  140         promoted_max = g_hash_table_lookup(rsc->
meta,
 
  142         if (promoted_max == NULL) {
 
  144             promoted_max = g_hash_table_lookup(rsc->
meta,
 
  148         promoted_node_max = g_hash_table_lookup(rsc->
meta,
 
  150         if (promoted_node_max == NULL) {
 
  152             promoted_node_max = g_hash_table_lookup(rsc->
meta,
 
  157         if (promoted_max == NULL) {
 
  158             clone_data->promoted_max = 1;
 
  164         if (promoted_node_max == NULL) {
 
  165             clone_data->promoted_node_max = 1;
 
  168                                &(clone_data->promoted_node_max), 0);
 
  176     if (max_clones_node == NULL) {
 
  177         clone_data->clone_node_max = 1;
 
  185     if (max_clones == NULL) {
 
  186         clone_data->clone_max = QB_MAX(1, g_list_length(data_set->
nodes));
 
  195                          "because anonymous clones support only one instance " 
  196                          "per node", rsc->
id);
 
  197         clone_data->clone_node_max = 1;
 
  201     pe_rsc_trace(rsc, 
"\tClone max: %d", clone_data->clone_max);
 
  202     pe_rsc_trace(rsc, 
"\tClone node max: %d", clone_data->clone_node_max);
 
  209     for (a_child = pcmk__xe_first_child(xml_obj); a_child != NULL;
 
  210          a_child = pcmk__xe_next(a_child)) {
 
  213             clone_data->xml_obj_child = a_child;
 
  218     if (clone_data->xml_obj_child == NULL) {
 
  239     if (clone_data->clone_max <= 0) {
 
  249         for (lpc = 0; lpc < clone_data->clone_max; lpc++) {
 
  256     pe_rsc_trace(rsc, 
"Added %d children to resource %s...", clone_data->clone_max, rsc->
id);
 
  265     for (; gIter != NULL; gIter = gIter->next) {
 
  267         gboolean child_active = child_rsc->
fns->
active(child_rsc, all);
 
  269         if (all == FALSE && child_active) {
 
  271         } 
else if (all && child_active == FALSE) {
 
  284 short_print(
char *list, 
const char *prefix, 
const char *
type, 
const char *suffix, 
long options, 
void *print_data)
 
  294         status_print(
"%s%s: [ %s ]%s", prefix, type, list, suffix);
 
  296         if (options & pe_print_html) {
 
  311     const char *target_role = g_hash_table_lookup(rsc->
meta,
 
  324     const char *target_role = configured_role_str(rsc);
 
  333 clone_print_xml(
pe_resource_t * rsc, 
const char *pre_text, 
long options, 
void *print_data)
 
  336     const char *target_role = configured_role_str(rsc);
 
  353     for (; gIter != NULL; gIter = gIter->next) {
 
  356         child_rsc->
fns->
print(child_rsc, child_text, options, print_data);
 
  376     for (gIter = rsc->
children; gIter != NULL; gIter = gIter->next) {
 
  396     char *list_text = NULL;
 
  397     char *child_text = NULL;
 
  398     char *stopped_list = NULL;
 
  399     size_t list_text_len = 0;
 
  400     size_t stopped_list_len = 0;
 
  402     GList *promoted_list = NULL;
 
  403     GList *started_list = NULL;
 
  406     clone_variant_data_t *clone_data = NULL;
 
  407     int active_instances = 0;
 
  409     if (pre_text == NULL) {
 
  414         clone_print_xml(rsc, pre_text, options, print_data);
 
  418     get_clone_variant_data(clone_data, rsc);
 
  423                  pre_text ? pre_text : 
"", rsc->
id, 
ID(clone_data->xml_obj_child),
 
  428     if (options & pe_print_html) {
 
  435     for (; gIter != NULL; gIter = gIter->next) {
 
  436         gboolean print_full = FALSE;
 
  438         gboolean partially_active = child_rsc->
fns->
active(child_rsc, FALSE);
 
  458         } 
else if (partially_active == FALSE) {
 
  462                 pcmk__add_word(&stopped_list, &stopped_list_len, child_rsc->
id);
 
  472         } 
else if (child_rsc->
fns->
active(child_rsc, TRUE)) {
 
  486                     promoted_list = g_list_append(promoted_list, location);
 
  489                     started_list = g_list_append(started_list, location);
 
  503             if (options & pe_print_html) {
 
  506             child_rsc->
fns->
print(child_rsc, child_text, options, print_data);
 
  507             if (options & pe_print_html) {
 
  515     for (gIter = promoted_list; gIter; gIter = gIter->next) {
 
  518         pcmk__add_word(&list_text, &list_text_len, host->
details->
uname);
 
  524     g_list_free(promoted_list);
 
  531     for (gIter = started_list; gIter; gIter = gIter->next) {
 
  534         pcmk__add_word(&list_text, &list_text_len, host->
details->
uname);
 
  542             short_print(list_text, child_text,
 
  547                         options, print_data);
 
  551         short_print(list_text, child_text, 
"Started", NULL, options, print_data);
 
  554     g_list_free(started_list);
 
  560         const char *state = 
"Stopped";
 
  564             state = 
"Stopped (disabled)";
 
  568             && (clone_data->clone_max > active_instances)) {
 
  576             stopped_list_len = 0;
 
  582                 list = g_hash_table_get_values(rsc->
known_on);
 
  586             for (nIter = list; nIter != NULL; nIter = nIter->next) {
 
  590                     pcmk__add_word(&stopped_list, &stopped_list_len,
 
  597         short_print(stopped_list, child_text, state, NULL, options, print_data);
 
  601     if (options & pe_print_html) {
 
  608 PCMK__OUTPUT_ARGS(
"clone", 
"unsigned int", 
"pe_resource_t *", 
"GList *", 
"GList *")
 
  612     unsigned int options = va_arg(args, 
unsigned int);
 
  614     GList *only_node = va_arg(args, GList *);
 
  615     GList *only_rsc = va_arg(args, GList *);
 
  619     gboolean printed_header = FALSE;
 
  620     gboolean print_everything = TRUE;
 
  629     for (; gIter != NULL; gIter = gIter->next) {
 
  636         if (child_rsc->
fns->
is_filtered(child_rsc, only_rsc, print_everything)) {
 
  640         if (!printed_header) {
 
  641             printed_header = TRUE;
 
  651                     "target_role", configured_role_str(rsc));
 
  655         out->message(out, crm_map_element_name(child_rsc->
xml), options,
 
  656                      child_rsc, only_node, only_rsc);
 
  659     if (printed_header) {
 
  666 PCMK__OUTPUT_ARGS(
"clone", 
"unsigned int", 
"pe_resource_t *", 
"GList *", 
"GList *")
 
  670     unsigned int options = va_arg(args, 
unsigned int);
 
  672     GList *only_node = va_arg(args, GList *);
 
  673     GList *only_rsc = va_arg(args, GList *);
 
  675     char *list_text = NULL;
 
  676     char *stopped_list = NULL;
 
  677     size_t list_text_len = 0;
 
  678     size_t stopped_list_len = 0;
 
  680     GList *promoted_list = NULL;
 
  681     GList *started_list = NULL;
 
  684     clone_variant_data_t *clone_data = NULL;
 
  685     int active_instances = 0;
 
  687     gboolean print_everything = TRUE;
 
  689     get_clone_variant_data(clone_data, rsc);
 
  698     out->begin_list(out, NULL, NULL, 
"Clone Set: %s [%s]%s%s%s%s",
 
  699                     rsc->
id, 
ID(clone_data->xml_obj_child),
 
  706     for (; gIter != NULL; gIter = gIter->next) {
 
  707         gboolean print_full = FALSE;
 
  709         gboolean partially_active = child_rsc->
fns->
active(child_rsc, FALSE);
 
  715         if (child_rsc->
fns->
is_filtered(child_rsc, only_rsc, print_everything)) {
 
  737         } 
else if (partially_active == FALSE) {
 
  741                 pcmk__add_word(&stopped_list, &stopped_list_len, child_rsc->
id);
 
  751         } 
else if (child_rsc->
fns->
active(child_rsc, TRUE)) {
 
  765                     promoted_list = g_list_append(promoted_list, location);
 
  768                     started_list = g_list_append(started_list, location);
 
  785             all = g_list_prepend(all, strdup(
"*"));
 
  786             out->message(out, crm_map_element_name(child_rsc->
xml), options,
 
  787                          child_rsc, only_node, all);
 
  788             g_list_free_full(all, free);
 
  800     for (gIter = promoted_list; gIter; gIter = gIter->next) {
 
  807         pcmk__add_word(&list_text, &list_text_len, host->
details->
uname);
 
  811     if (list_text != NULL) {
 
  813         g_list_free(promoted_list);
 
  821     for (gIter = started_list; gIter; gIter = gIter->next) {
 
  828         pcmk__add_word(&list_text, &list_text_len, host->
details->
uname);
 
  832     if (list_text != NULL) {
 
  837                 out->list_item(out, NULL,
 
  846             out->list_item(out, NULL, 
"Started: [ %s ]", list_text);
 
  849         g_list_free(started_list);
 
  856         const char *state = 
"Stopped";
 
  860             state = 
"Stopped (disabled)";
 
  864             && (clone_data->clone_max > active_instances)) {
 
  872             stopped_list_len = 0;
 
  878                 list = g_hash_table_get_values(rsc->
known_on);
 
  882             for (nIter = list; nIter != NULL; nIter = nIter->next) {
 
  887                     pcmk__add_word(&stopped_list, &stopped_list_len,
 
  894         if (stopped_list != NULL) {
 
  895             out->list_item(out, NULL, 
"%s: [ %s ]", state, stopped_list);
 
  897             stopped_list_len = 0;
 
  906 PCMK__OUTPUT_ARGS(
"clone", 
"unsigned int", 
"pe_resource_t *", 
"GList *", 
"GList *")
 
  910     unsigned int options = va_arg(args, 
unsigned int);
 
  912     GList *only_node = va_arg(args, GList *);
 
  913     GList *only_rsc = va_arg(args, GList *);
 
  915     char *list_text = NULL;
 
  916     char *stopped_list = NULL;
 
  917     size_t list_text_len = 0;
 
  918     size_t stopped_list_len = 0;
 
  920     GList *promoted_list = NULL;
 
  921     GList *started_list = NULL;
 
  924     clone_variant_data_t *clone_data = NULL;
 
  925     int active_instances = 0;
 
  927     gboolean print_everything = TRUE;
 
  929     get_clone_variant_data(clone_data, rsc);
 
  938     out->begin_list(out, NULL, NULL, 
"Clone Set: %s [%s]%s%s%s%s",
 
  939                     rsc->
id, 
ID(clone_data->xml_obj_child),
 
  946     for (; gIter != NULL; gIter = gIter->next) {
 
  947         gboolean print_full = FALSE;
 
  949         gboolean partially_active = child_rsc->
fns->
active(child_rsc, FALSE);
 
  955         if (child_rsc->
fns->
is_filtered(child_rsc, only_rsc, print_everything)) {
 
  977         } 
else if (partially_active == FALSE) {
 
  981                 pcmk__add_word(&stopped_list, &stopped_list_len, child_rsc->
id);
 
  991         } 
else if (child_rsc->
fns->
active(child_rsc, TRUE)) {
 
 1005                     promoted_list = g_list_append(promoted_list, location);
 
 1008                     started_list = g_list_append(started_list, location);
 
 1025             all = g_list_prepend(all, strdup(
"*"));
 
 1026             out->message(out, crm_map_element_name(child_rsc->
xml), options,
 
 1027                          child_rsc, only_node, all);
 
 1028             g_list_free_full(all, free);
 
 1040     for (gIter = promoted_list; gIter; gIter = gIter->next) {
 
 1047         pcmk__add_word(&list_text, &list_text_len, host->
details->
uname);
 
 1051     if (list_text != NULL) {
 
 1053         g_list_free(promoted_list);
 
 1061     for (gIter = started_list; gIter; gIter = gIter->next) {
 
 1068         pcmk__add_word(&list_text, &list_text_len, host->
details->
uname);
 
 1072     if (list_text != NULL) {
 
 1078                                "[ %s ]", list_text);
 
 1083             out->list_item(out, 
"Started", 
"[ %s ]", list_text);
 
 1086         g_list_free(started_list);
 
 1092         const char *state = 
"Stopped";
 
 1096             state = 
"Stopped (disabled)";
 
 1100             && (clone_data->clone_max > active_instances)) {
 
 1107             stopped_list = NULL;
 
 1108             stopped_list_len = 0;
 
 1114                 list = g_hash_table_get_values(rsc->
known_on);
 
 1118             for (nIter = list; nIter != NULL; nIter = nIter->next) {
 
 1123                     pcmk__add_word(&stopped_list, &stopped_list_len,
 
 1130         if (stopped_list != NULL) {
 
 1131             out->list_item(out, state, 
"[ %s ]", stopped_list);
 
 1144     clone_variant_data_t *clone_data = NULL;
 
 1146     get_clone_variant_data(clone_data, rsc);
 
 1150     for (GList *gIter = rsc->
children; gIter != NULL; gIter = gIter->next) {
 
 1156         child_rsc->
xml = NULL;
 
 1160         child_rsc->
fns->
free(child_rsc);
 
 1166         CRM_ASSERT(clone_data->demote_notify == NULL);
 
 1168         CRM_ASSERT(clone_data->start_notify == NULL);
 
 1169         CRM_ASSERT(clone_data->promote_notify == NULL);
 
 1181     for (; gIter != NULL; gIter = gIter->next) {
 
 1185         if (a_role > clone_role) {
 
 1186             clone_role = a_role;
 
 1205     if (pe_rsc_is_clone(rsc)) {
 
 1206         clone_variant_data_t *clone_data = NULL;
 
 1208         get_clone_variant_data(clone_data, rsc);
 
 1209         if (clone_data->clone_max == g_list_length(data_set->
nodes)) {
 
 1219     gboolean passes = FALSE;
 
 1220     clone_variant_data_t *clone_data = NULL;
 
 1225         get_clone_variant_data(clone_data, rsc);
 
 1229             for (GList *gIter = rsc->
children; gIter != NULL; gIter = gIter->next) {
 
#define CRM_CHECK(expr, failure_action)
 
pe_node_t * pe_find_node(GList *node_list, const char *uname)
 
bool is_set_recursive(pe_resource_t *rsc, long long flag, bool any)
 
#define PROMOTED_INSTANCES
 
enum rsc_role_e(* state)(const pe_resource_t *, gboolean)
 
int pcmk__scan_min_int(const char *text, int *result, int minimum)
 
#define UNPROMOTED_INSTANCES
 
gboolean pcmk__str_in_list(GList *lst, const gchar *s)
 
#define XML_RSC_ATTR_INCARNATION
 
#define pcmk__config_err(fmt...)
 
void pe__force_anon(const char *standard, pe_resource_t *rsc, const char *rid, pe_working_set_t *data_set)
 
resource_object_functions_t * fns
 
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value. 
 
pe_resource_t * pe_find_resource(GList *rsc_list, const char *id_rh)
 
#define PCMK_XE_PROMOTED_NODE_MAX_LEGACY
 
#define XML_RSC_ATTR_STICKINESS
 
enum crm_ais_msg_types type
 
#define XML_RSC_ATTR_INCARNATION_MAX
 
#define PCMK_XE_PROMOTED_MAX_LEGACY
 
void clone_free(pe_resource_t *rsc)
 
int pe__clone_html(pcmk__output_t *out, va_list args)
 
xmlNode * copy_xml(xmlNode *src_node)
 
void pe__set_resource_flags_recursive(pe_resource_t *rsc, uint64_t flags)
 
const char * role2text(enum rsc_role_e role)
 
enum rsc_role_e clone_resource_state(const pe_resource_t *rsc, gboolean current)
 
gboolean clone_active(pe_resource_t *rsc, gboolean all)
 
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute. 
 
#define XML_CIB_TAG_RESOURCE
 
#define PCMK__OUTPUT_ARGS(ARGS...)
 
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)
 
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
 
pe_resource_t * find_clone_instance(pe_resource_t *rsc, const char *sub_id, pe_working_set_t *data_set)
 
void common_free(pe_resource_t *rsc)
 
#define pe_rsc_promotable
 
#define XML_RSC_ATTR_ORDERED
 
void clone_print(pe_resource_t *rsc, const char *pre_text, long options, void *print_data)
 
#define XML_RSC_ATTR_INCARNATION_NODEMAX
 
pe_resource_t * pe__create_clone_child(pe_resource_t *rsc, pe_working_set_t *data_set)
 
#define XML_RSC_ATTR_TARGET_ROLE
 
void free_xml(xmlNode *child)
 
enum rsc_role_e text2role(const char *role)
 
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
 
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
 
void(* print)(pe_resource_t *, const char *, long, void *)
 
#define XML_RSC_ATTR_UNIQUE
 
#define XML_RSC_ATTR_PROMOTED_MAX
 
gboolean(* is_filtered)(pe_resource_t *, GList *, gboolean)
 
Cluster status and scheduling. 
 
bool pcmk__rsc_filtered_by_node(pe_resource_t *rsc, GList *only_node)
 
int pe__clone_text(pcmk__output_t *out, va_list args)
 
void add_hash_param(GHashTable *hash, const char *name, const char *value)
 
gboolean clone_unpack(pe_resource_t *rsc, pe_working_set_t *data_set)
 
const char * rsc_printable_id(pe_resource_t *rsc)
 
#define status_print(fmt, args...)
 
This structure contains everything that makes up a single output formatter. 
 
void(* free)(pe_resource_t *)
 
rsc_role_e
Possible roles that a resource can be in. 
 
#define XML_RSC_ATTR_PROMOTED_NODEMAX
 
bool pe__is_universal_clone(pe_resource_t *rsc, pe_working_set_t *data_set)
 
#define pe_rsc_failure_ignored
 
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
 
gboolean common_unpack(xmlNode *xml_obj, pe_resource_t **rsc, pe_resource_t *parent, pe_working_set_t *data_set)
 
gboolean crm_is_true(const char *s)
 
#define XML_CIB_TAG_GROUP
 
#define pe_rsc_trace(rsc, fmt, args...)
 
gboolean(* active)(pe_resource_t *, gboolean)
 
bool pe__resource_is_disabled(pe_resource_t *rsc)
 
gint sort_node_uname(gconstpointer a, gconstpointer b)
 
gboolean pe__clone_is_filtered(pe_resource_t *rsc, GList *only_rsc, gboolean check_parent)
 
GHashTable * allowed_nodes