Esempio n. 1
0
void
group_rsc_colocation_rh(pe_resource_t *rsc_lh, pe_resource_t *rsc_rh,
                        rsc_colocation_t *constraint,
                        pe_working_set_t *data_set)
{
    GListPtr gIter = rsc_rh->children;
    group_variant_data_t *group_data = NULL;

    get_group_variant_data(group_data, rsc_rh);
    CRM_CHECK(rsc_lh->variant == pe_native, return);

    pe_rsc_trace(rsc_rh, "Processing RH of constraint %s", constraint->id);
    print_resource(LOG_TRACE, "LHS", rsc_lh, TRUE);

    if (is_set(rsc_rh->flags, pe_rsc_provisional)) {
        return;

    } else if (group_data->colocated && group_data->first_child) {
        if (constraint->score >= INFINITY) {
            /* Ensure RHS is _fully_ up before can start LHS */
            group_data->last_child->cmds->rsc_colocation_rh(rsc_lh,
                                                            group_data->last_child,
                                                            constraint,
                                                            data_set);
        } else {
            /* A partially active RHS is fine */
            group_data->first_child->cmds->rsc_colocation_rh(rsc_lh,
                                                             group_data->first_child,
                                                             constraint,
                                                             data_set);
        }

        return;

    } else if (constraint->score >= INFINITY) {
        crm_config_err("%s: Cannot perform mandatory colocation with"
                       " non-colocated group: %s", rsc_lh->id, rsc_rh->id);
        return;
    }

    for (; gIter != NULL; gIter = gIter->next) {
        resource_t *child_rsc = (resource_t *) gIter->data;

        child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint,
                                           data_set);
    }
}
Esempio n. 2
0
const char *
cluster_option(GHashTable* options, gboolean(*validate)(const char*),
	       const char *name, const char *old_name, const char *def_value)
{
	const char *value = NULL;
	CRM_ASSERT(name != NULL);

	if(options != NULL) {
		value = g_hash_table_lookup(options, name);
	}

	if(value == NULL && old_name && options != NULL) {
		value = g_hash_table_lookup(options, old_name);
		if(value != NULL) {
			crm_config_warn("Using deprecated name '%s' for"
				       " cluster option '%s'", old_name, name);
			g_hash_table_insert(
				options, crm_strdup(name), crm_strdup(value));
			value = g_hash_table_lookup(options, old_name);
		}
	}

	if(value == NULL) {
		crm_debug("Using default value '%s' for cluster option '%s'",
			  def_value, name);

		if(options == NULL) {
			return def_value;
		}
		
		g_hash_table_insert(
			options, crm_strdup(name), crm_strdup(def_value));
		value = g_hash_table_lookup(options, name);
	}
	
	if(validate && validate(value) == FALSE) {
		crm_config_err("Value '%s' for cluster option '%s' is invalid."
			      "  Defaulting to %s", value, name, def_value);
		g_hash_table_replace(options, crm_strdup(name),
				     crm_strdup(def_value));
		value = g_hash_table_lookup(options, name);
	}
	
	return value;
}
Esempio n. 3
0
void
group_rsc_colocation_lh(pe_resource_t *rsc_lh, pe_resource_t *rsc_rh,
                        rsc_colocation_t *constraint,
                        pe_working_set_t *data_set)
{
    GListPtr gIter = NULL;
    group_variant_data_t *group_data = NULL;

    if (rsc_lh == NULL) {
        pe_err("rsc_lh was NULL for %s", constraint->id);
        return;

    } else if (rsc_rh == NULL) {
        pe_err("rsc_rh was NULL for %s", constraint->id);
        return;
    }

    gIter = rsc_lh->children;
    pe_rsc_trace(rsc_lh, "Processing constraints from %s", rsc_lh->id);

    get_group_variant_data(group_data, rsc_lh);

    if (group_data->colocated) {
        group_data->first_child->cmds->rsc_colocation_lh(group_data->first_child,
                                                         rsc_rh, constraint,
                                                         data_set);
        return;

    } else if (constraint->score >= INFINITY) {
        crm_config_err("%s: Cannot perform mandatory colocation"
                       " between non-colocated group and %s", rsc_lh->id, rsc_rh->id);
        return;
    }

    for (; gIter != NULL; gIter = gIter->next) {
        resource_t *child_rsc = (resource_t *) gIter->data;

        child_rsc->cmds->rsc_colocation_lh(child_rsc, rsc_rh, constraint,
                                           data_set);
    }
}
Esempio n. 4
0
node_t *
master_color(resource_t * rsc, node_t * prefer, pe_working_set_t * data_set)
{
    int promoted = 0;
    GListPtr gIter = NULL;
    GListPtr gIter2 = NULL;

    GHashTableIter iter;
    node_t *node = NULL;
    node_t *chosen = NULL;
    node_t *cons_node = NULL;
    enum rsc_role_e next_role = RSC_ROLE_UNKNOWN;

    clone_variant_data_t *clone_data = NULL;

    get_clone_variant_data(clone_data, rsc);

    if (is_not_set(rsc->flags, pe_rsc_provisional)) {
        return NULL;

    } else if (is_set(rsc->flags, pe_rsc_allocating)) {
        crm_debug("Dependency loop detected involving %s", rsc->id);
        return NULL;
    }

    apply_master_prefs(rsc);

    clone_color(rsc, prefer, data_set);

    set_bit(rsc->flags, pe_rsc_allocating);

    /* count now tracks the number of masters allocated */
    g_hash_table_iter_init(&iter, rsc->allowed_nodes);
    while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
        node->count = 0;
    }

    /*
     * assign priority
     */
    gIter = rsc->children;
    for (; gIter != NULL; gIter = gIter->next) {
        GListPtr list = NULL;
        resource_t *child_rsc = (resource_t *) gIter->data;

        crm_trace("Assigning priority for %s: %s", child_rsc->id,
                    role2text(child_rsc->next_role));

        if (child_rsc->fns->state(child_rsc, TRUE) == RSC_ROLE_STARTED) {
            set_role_slave(child_rsc, TRUE);
        }

        chosen = child_rsc->fns->location(child_rsc, &list, FALSE);
        if (g_list_length(list) > 1) {
            crm_config_err("Cannot promote non-colocated child %s", child_rsc->id);
        }

        g_list_free(list);
        if (chosen == NULL) {
            continue;
        }

        next_role = child_rsc->fns->state(child_rsc, FALSE);
        switch (next_role) {
            case RSC_ROLE_STARTED:
            case RSC_ROLE_UNKNOWN:
                CRM_CHECK(chosen != NULL, break);
                /*
                 * Default to -1 if no value is set
                 *
                 * This allows master locations to be specified
                 * based solely on rsc_location constraints,
                 * but prevents anyone from being promoted if
                 * neither a constraint nor a master-score is present
                 */
                child_rsc->priority = master_score(child_rsc, chosen, -1);
                break;

            case RSC_ROLE_SLAVE:
            case RSC_ROLE_STOPPED:
                child_rsc->priority = -INFINITY;
                break;
            case RSC_ROLE_MASTER:
                /* We will arrive here if we're re-creating actions after a stonith
                 */
                break;
            default:
                CRM_CHECK(FALSE /* unhandled */ ,
                          crm_err("Unknown resource role: %d for %s", next_role, child_rsc->id));
        }

        apply_master_location(child_rsc->rsc_location);
        apply_master_location(rsc->rsc_location);

        gIter2 = child_rsc->rsc_cons;
        for (; gIter2 != NULL; gIter2 = gIter2->next) {
            rsc_colocation_t *cons = (rsc_colocation_t *) gIter2->data;

            child_rsc->cmds->rsc_colocation_lh(child_rsc, cons->rsc_rh, cons);
        }

        child_rsc->sort_index = child_rsc->priority;
        crm_trace("Assigning priority for %s: %d", child_rsc->id, child_rsc->priority);

        if (next_role == RSC_ROLE_MASTER) {
            child_rsc->sort_index = INFINITY;
        }
    }

    dump_node_scores(LOG_DEBUG_3, rsc, "Pre merge", rsc->allowed_nodes);
    master_promotion_order(rsc, data_set);

    /* mark the first N as masters */

    gIter = rsc->children;
    for (; gIter != NULL; gIter = gIter->next) {
        resource_t *child_rsc = (resource_t *) gIter->data;
        char *score = score2char(child_rsc->sort_index);

        chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
        if (show_scores) {
            fprintf(stdout, "%s promotion score on %s: %s\n",
                    child_rsc->id, chosen ? chosen->details->uname : "none", score);

        } else {
            do_crm_log(scores_log_level, "%s promotion score on %s: %s",
                                child_rsc->id, chosen ? chosen->details->uname : "none", score);
        }
        crm_free(score);

        chosen = NULL;          /* nuke 'chosen' so that we don't promote more than the
                                 * required number of instances
                                 */

        if (child_rsc->sort_index < 0) {
            crm_trace("Not supposed to promote child: %s", child_rsc->id);

        } else if (promoted < clone_data->master_max || is_not_set(rsc->flags, pe_rsc_managed)) {
            chosen = can_be_master(child_rsc);
        }

        crm_debug("%s master score: %d", child_rsc->id, child_rsc->priority);

        if (chosen == NULL) {
            set_role_slave(child_rsc, FALSE);
            continue;
        }

        chosen->count++;
        crm_info("Promoting %s (%s %s)",
                 child_rsc->id, role2text(child_rsc->role), chosen->details->uname);
        set_role_master(child_rsc);
        promoted++;
    }

    clone_data->masters_allocated = promoted;
    crm_info("%s: Promoted %d instances of a possible %d to master",
             rsc->id, promoted, clone_data->master_max);

    clear_bit(rsc->flags, pe_rsc_provisional);
    clear_bit(rsc->flags, pe_rsc_allocating);

    return NULL;
}
Esempio n. 5
0
int
main(int argc, char **argv)
{
    xmlNode *cib_object = NULL;
    xmlNode *status = NULL;
    int argerr = 0;
    int flag;
    int option_index = 0;

    pe_working_set_t data_set;
    cib_t *cib_conn = NULL;
    int rc = cib_ok;

    gboolean xml_stdin = FALSE;
    const char *xml_tag = NULL;
    const char *xml_file = NULL;
    const char *xml_string = NULL;

    g_log_set_handler(NULL,
                      G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL
                      | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE
                      | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG
                      | G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL, cl_glib_msg_handler, NULL);

    /* and for good measure... - this enum is a bit field (!) */
    g_log_set_always_fatal((GLogLevelFlags) 0); /*value out of range */

    crm_log_init_quiet(NULL, LOG_ERR, FALSE, TRUE, argc, argv);
    crm_set_options(NULL, "[modifiers] data_source", long_options,
                    "Check a (complete) confiuration for syntax and common conceptual errors."
                    "\n\nChecks the well-formedness of an XML configuration, its conformance to the configured DTD/schema and for the presence of common misconfigurations."
                    "\n\nIt reports two classes of problems, errors and warnings."
                    " Errors must be fixed before the cluster will work properly."
                    " However, it is left up to the administrator to decide if the warnings should also be fixed.");

    while (1) {
        flag = crm_get_option(argc, argv, &option_index);
        if (flag == -1)
            break;

        switch (flag) {
#ifdef HAVE_GETOPT_H
            case 0:
                printf("option %s", long_options[option_index].name);
                if (optarg)
                    printf(" with arg %s", optarg);
                printf("\n");

                break;
#endif

            case 'X':
                crm_debug_2("Option %c => %s", flag, optarg);
                xml_string = crm_strdup(optarg);
                break;
            case 'x':
                crm_debug_2("Option %c => %s", flag, optarg);
                xml_file = crm_strdup(optarg);
                break;
            case 'p':
                xml_stdin = TRUE;
                break;
            case 'S':
                cib_save = crm_strdup(optarg);
                break;
            case 'V':
                alter_debug(DEBUG_INC);
                break;
            case 'L':
                USE_LIVE_CIB = TRUE;
                break;
            case '$':
            case '?':
                crm_help(flag, LSB_EXIT_OK);
                break;
            default:
                fprintf(stderr, "Option -%c is not yet supported\n", flag);
                ++argerr;
                break;
        }
    }

    if (optind < argc) {
        printf("non-option ARGV-elements: ");
        while (optind < argc) {
            printf("%s ", argv[optind++]);
        }
        printf("\n");
    }

    if (optind > argc) {
        ++argerr;
    }

    if (argerr) {
        crm_err("%d errors in option parsing", argerr);
        crm_help(flag, LSB_EXIT_GENERIC);
    }

    crm_info("=#=#=#=#= Getting XML =#=#=#=#=");

    if (USE_LIVE_CIB) {
        cib_conn = cib_new();
        rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
    }

    if (USE_LIVE_CIB) {
        if (rc == cib_ok) {
            int options = cib_scope_local | cib_sync_call;

            crm_info("Reading XML from: live cluster");
            rc = cib_conn->cmds->query(cib_conn, NULL, &cib_object, options);
        }

        if (rc != cib_ok) {
            fprintf(stderr, "Live CIB query failed: %s\n", cib_error2string(rc));
            return 3;
        }
        if (cib_object == NULL) {
            fprintf(stderr, "Live CIB query failed: empty result\n");
            return 3;
        }

    } else if (xml_file != NULL) {
        cib_object = filename2xml(xml_file);
        if (cib_object == NULL) {
            fprintf(stderr, "Couldn't parse input file: %s\n", xml_file);
            return 4;
        }

    } else if (xml_string != NULL) {
        cib_object = string2xml(xml_string);
        if (cib_object == NULL) {
            fprintf(stderr, "Couldn't parse input string: %s\n", xml_string);
            return 4;
        }
    } else if (xml_stdin) {
        cib_object = stdin2xml();
        if (cib_object == NULL) {
            fprintf(stderr, "Couldn't parse input from STDIN.\n");
            return 4;
        }

    } else {
        fprintf(stderr, "No configuration source specified."
                "  Use --help for usage information.\n");
        return 5;
    }

    xml_tag = crm_element_name(cib_object);
    if (safe_str_neq(xml_tag, XML_TAG_CIB)) {
        fprintf(stderr,
                "This tool can only check complete configurations (ie. those starting with <cib>).\n");
        return 6;
    }

    if (cib_save != NULL) {
        write_xml_file(cib_object, cib_save, FALSE);
    }

    status = get_object_root(XML_CIB_TAG_STATUS, cib_object);
    if (status == NULL) {
        create_xml_node(cib_object, XML_CIB_TAG_STATUS);
    }

    if (validate_xml(cib_object, NULL, FALSE) == FALSE) {
        crm_config_err("CIB did not pass DTD/schema validation");
        free_xml(cib_object);
        cib_object = NULL;

    } else if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
        crm_config_error = TRUE;
        free_xml(cib_object);
        cib_object = NULL;
        fprintf(stderr, "The cluster will NOT be able to use this configuration.\n");
        fprintf(stderr, "Please manually update the configuration to conform to the %s syntax.\n",
                LATEST_SCHEMA_VERSION);
    }

    set_working_set_defaults(&data_set);
    if (cib_object == NULL) {
    } else if (USE_LIVE_CIB) {
        /* we will always have a status section and can do a full simulation */
        do_calculations(&data_set, cib_object, NULL);
        cleanup_alloc_calculations(&data_set);

    } else {
        data_set.now = new_ha_date(TRUE);
        data_set.input = cib_object;
        stage0(&data_set);
        cleanup_alloc_calculations(&data_set);
    }

    if (crm_config_error) {
        fprintf(stderr, "Errors found during check: config not valid\n");
        if (crm_log_level < LOG_WARNING) {
            fprintf(stderr, "  -V may provide more details\n");
        }
        rc = 2;

    } else if (crm_config_warning) {
        fprintf(stderr, "Warnings found during check: config may not be valid\n");
        if (crm_log_level < LOG_WARNING) {
            fprintf(stderr, "  Use -V for more details\n");
        }
        rc = 1;
    }

    if (USE_LIVE_CIB) {
        cib_conn->cmds->signoff(cib_conn);
        cib_delete(cib_conn);
    }

    return rc;
}
Esempio n. 6
0
gboolean
group_unpack(resource_t * rsc, pe_working_set_t * data_set)
{
    xmlNode *xml_obj = rsc->xml;
    xmlNode *xml_native_rsc = NULL;
    group_variant_data_t *group_data = NULL;
    const char *group_ordered = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_ORDERED);
    const char *group_colocated = g_hash_table_lookup(rsc->meta, "collocated");
    const char *clone_id = NULL;

    pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);

    group_data = calloc(1, sizeof(group_variant_data_t));
    group_data->num_children = 0;
    group_data->first_child = NULL;
    group_data->last_child = NULL;
    rsc->variant_opaque = group_data;

    group_data->ordered = TRUE;
    group_data->colocated = TRUE;

    if (group_ordered != NULL) {
        crm_str_to_boolean(group_ordered, &(group_data->ordered));
    }
    if (group_colocated != NULL) {
        crm_str_to_boolean(group_colocated, &(group_data->colocated));
    }

    clone_id = crm_element_value(rsc->xml, XML_RSC_ATTR_INCARNATION);

    for (xml_native_rsc = __xml_first_child(xml_obj); xml_native_rsc != NULL;
            xml_native_rsc = __xml_next(xml_native_rsc)) {
        if (crm_str_eq((const char *)xml_native_rsc->name, XML_CIB_TAG_RESOURCE, TRUE)) {
            resource_t *new_rsc = NULL;

            crm_xml_add(xml_native_rsc, XML_RSC_ATTR_INCARNATION, clone_id);
            if (common_unpack(xml_native_rsc, &new_rsc, rsc, data_set) == FALSE) {
                pe_err("Failed unpacking resource %s", crm_element_value(xml_obj, XML_ATTR_ID));
                if (new_rsc != NULL && new_rsc->fns != NULL) {
                    new_rsc->fns->free(new_rsc);
                }
            }

            group_data->num_children++;
            rsc->children = g_list_append(rsc->children, new_rsc);

            if (group_data->first_child == NULL) {
                group_data->first_child = new_rsc;
            }
            group_data->last_child = new_rsc;
            print_resource(LOG_DEBUG_3, "Added ", new_rsc, FALSE);
        }
    }

    if (group_data->num_children == 0) {
#if 0
        /* Bug #1287 */
        crm_config_err("Group %s did not have any children", rsc->id);
        return FALSE;
#else
        crm_config_warn("Group %s did not have any children", rsc->id);
        return TRUE;
#endif
    }

    pe_rsc_trace(rsc, "Added %d children to resource %s...", group_data->num_children, rsc->id);

    return TRUE;
}
Esempio n. 7
0
const char *
cluster_option(GHashTable * options, gboolean(*validate) (const char *),
               const char *name, const char *old_name, const char *def_value)
{
    const char *value = NULL;
    char *new_value = NULL;

    CRM_ASSERT(name != NULL);

    if (options) {
        value = g_hash_table_lookup(options, name);

        if ((value == NULL) && old_name) {
            value = g_hash_table_lookup(options, old_name);
            if (value != NULL) {
                crm_config_warn("Support for legacy name '%s' for cluster option '%s'"
                                " is deprecated and will be removed in a future release",
                                old_name, name);

                // Inserting copy with current name ensures we only warn once
                new_value = strdup(value);
                g_hash_table_insert(options, strdup(name), new_value);
                value = new_value;
            }
        }

        if (value && validate && (validate(value) == FALSE)) {
            crm_config_err("Resetting cluster option '%s' to default: value '%s' is invalid",
                           name, value);
            value = NULL;
        }

        if (value) {
            return value;
        }
    }

    // No value found, use default
    value = def_value;

    if (value == NULL) {
        crm_trace("No value or default provided for cluster option '%s'",
                  name);
        return NULL;
    }

    if (validate) {
        CRM_CHECK(validate(value) != FALSE,
                  crm_err("Bug: default value for cluster option '%s' is invalid", name);
                  return NULL);
    }

    crm_trace("Using default value '%s' for cluster option '%s'",
              value, name);
    if (options) {
        new_value = strdup(value);
        g_hash_table_insert(options, strdup(name), new_value);
        value = new_value;
    }
    return value;
}
Esempio n. 8
0
static node_t *
color_instance(resource_t * rsc, node_t * prefer, gboolean all_coloc, int limit, pe_working_set_t * data_set)
{
    node_t *chosen = NULL;
    GHashTable *backup = NULL;

    CRM_ASSERT(rsc);
    pe_rsc_trace(rsc, "Checking allocation of %s (preferring %s, using %s parent colocations)",
                 rsc->id, (prefer? prefer->details->uname: "none"),
                 (all_coloc? "all" : "some"));

    if (is_not_set(rsc->flags, pe_rsc_provisional)) {
        return rsc->fns->location(rsc, NULL, FALSE);

    } else if (is_set(rsc->flags, pe_rsc_allocating)) {
        pe_rsc_debug(rsc, "Dependency loop detected involving %s", rsc->id);
        return NULL;
    }

    /* Only include positive colocation preferences of dependent resources
     * if not every node will get a copy of the clone
     */
    append_parent_colocation(rsc->parent, rsc, all_coloc);

    if (prefer) {
        node_t *local_prefer = g_hash_table_lookup(rsc->allowed_nodes, prefer->details->id);

        if (local_prefer == NULL || local_prefer->weight < 0) {
            pe_rsc_trace(rsc, "Not pre-allocating %s to %s - unavailable", rsc->id,
                         prefer->details->uname);
            return NULL;
        }
    }

    can_run_instance(rsc, NULL, limit);

    backup = node_hash_dup(rsc->allowed_nodes);
    chosen = rsc->cmds->allocate(rsc, prefer, data_set);
    if (chosen && prefer && (chosen->details != prefer->details)) {
        crm_info("Not pre-allocating %s to %s because %s is better",
                 rsc->id, prefer->details->uname, chosen->details->uname);
        g_hash_table_destroy(rsc->allowed_nodes);
        rsc->allowed_nodes = backup;
        native_deallocate(rsc);
        chosen = NULL;
        backup = NULL;
    }
    if (chosen) {
        pe_node_t *local_node = parent_node_instance(rsc, chosen);

        if (local_node) {
            local_node->count++;

        } else if (is_set(rsc->flags, pe_rsc_managed)) {
            /* what to do? we can't enforce per-node limits in this case */
            crm_config_err("%s not found in %s (list=%d)",
                           chosen->details->id, rsc->parent->id,
                           g_hash_table_size(rsc->parent->allowed_nodes));
        }
    }

    if(backup) {
        g_hash_table_destroy(backup);
    }
    return chosen;
}
Esempio n. 9
0
void
clone_rsc_colocation_rh(pe_resource_t *rsc_lh, pe_resource_t *rsc_rh,
                        rsc_colocation_t *constraint,
                        pe_working_set_t *data_set)
{
    GListPtr gIter = NULL;
    gboolean do_interleave = FALSE;
    const char *interleave_s = NULL;

    CRM_CHECK(constraint != NULL, return);
    CRM_CHECK(rsc_lh != NULL, pe_err("rsc_lh was NULL for %s", constraint->id); return);
    CRM_CHECK(rsc_rh != NULL, pe_err("rsc_rh was NULL for %s", constraint->id); return);
    CRM_CHECK(rsc_lh->variant == pe_native, return);

    pe_rsc_trace(rsc_rh, "Processing constraint %s: %s -> %s %d",
                 constraint->id, rsc_lh->id, rsc_rh->id, constraint->score);

    if (is_set(rsc_rh->flags, pe_rsc_promotable)) {
        if (is_set(rsc_rh->flags, pe_rsc_provisional)) {
            pe_rsc_trace(rsc_rh, "%s is still provisional", rsc_rh->id);
            return;
        } else if (constraint->role_rh == RSC_ROLE_UNKNOWN) {
            pe_rsc_trace(rsc_rh, "Handling %s as a clone colocation", constraint->id);
        } else {
            promotable_colocation_rh(rsc_lh, rsc_rh, constraint, data_set);
            return;
        }
    }

    /* only the LHS side needs to be labeled as interleave */
    interleave_s = g_hash_table_lookup(constraint->rsc_lh->meta, XML_RSC_ATTR_INTERLEAVE);
    if(crm_is_true(interleave_s) && constraint->rsc_lh->variant > pe_group) {
        // TODO: Do we actually care about multiple RH copies sharing a LH copy anymore?
        if (copies_per_node(constraint->rsc_lh) != copies_per_node(constraint->rsc_rh)) {
            crm_config_err("Cannot interleave %s and %s because"
                           " they do not support the same number of copies per node",
                           constraint->rsc_lh->id, constraint->rsc_rh->id);

        } else {
            do_interleave = TRUE;
        }
    }

    if (is_set(rsc_rh->flags, pe_rsc_provisional)) {
        pe_rsc_trace(rsc_rh, "%s is still provisional", rsc_rh->id);
        return;

    } else if (do_interleave) {
        resource_t *rh_child = NULL;

        rh_child = find_compatible_child(rsc_lh, rsc_rh, RSC_ROLE_UNKNOWN,
                                         FALSE, data_set);

        if (rh_child) {
            pe_rsc_debug(rsc_rh, "Pairing %s with %s", rsc_lh->id, rh_child->id);
            rsc_lh->cmds->rsc_colocation_lh(rsc_lh, rh_child, constraint,
                                            data_set);

        } else if (constraint->score >= INFINITY) {
            crm_notice("Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id);
            assign_node(rsc_lh, NULL, TRUE);

        } else {
            pe_rsc_debug(rsc_rh, "Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id);
        }

        return;

    } else if (constraint->score >= INFINITY) {
        GListPtr rhs = NULL;

        gIter = rsc_rh->children;
        for (; gIter != NULL; gIter = gIter->next) {
            resource_t *child_rsc = (resource_t *) gIter->data;
            node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);

            if (chosen != NULL && is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
                pe_rsc_trace(rsc_rh, "Allowing %s: %s %d", constraint->id, chosen->details->uname, chosen->weight);
                rhs = g_list_prepend(rhs, chosen);
            }
        }

        node_list_exclude(rsc_lh->allowed_nodes, rhs, FALSE);
        g_list_free(rhs);
        return;
    }

    gIter = rsc_rh->children;
    for (; gIter != NULL; gIter = gIter->next) {
        resource_t *child_rsc = (resource_t *) gIter->data;

        child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint,
                                           data_set);
    }
}
Esempio n. 10
0
gboolean
clone_unpack(resource_t * rsc, pe_working_set_t * data_set)
{
    int lpc = 0;
    const char *type = NULL;
    int num_xml_children = 0;
    xmlNode *a_child = NULL;
    xmlNode *xml_obj = rsc->xml;
    clone_variant_data_t *clone_data = NULL;

    const char *ordered = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_ORDERED);
    const char *interleave = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERLEAVE);
    const char *max_clones = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_MAX);
    const char *max_clones_node = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_NODEMAX);

    pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);

    clone_data = calloc(1, sizeof(clone_variant_data_t));
    rsc->variant_opaque = clone_data;
    clone_data->interleave = FALSE;
    clone_data->ordered = FALSE;

    clone_data->active_clones = 0;
    clone_data->xml_obj_child = NULL;
    clone_data->clone_node_max = crm_parse_int(max_clones_node, "1");

    if (max_clones) {
        clone_data->clone_max = crm_parse_int(max_clones, "1");

    } else if (g_list_length(data_set->nodes) > 0) {
        clone_data->clone_max = g_list_length(data_set->nodes);

    } else {
        clone_data->clone_max = 1;      /* Handy during crm_verify */
    }

    if (crm_is_true(interleave)) {
        clone_data->interleave = TRUE;
    }
    if (crm_is_true(ordered)) {
        clone_data->ordered = TRUE;
    }
    if ((rsc->flags & pe_rsc_unique) == 0 && clone_data->clone_node_max > 1) {
        crm_config_err("Anonymous clones (%s) may only support one copy per node", rsc->id);
        clone_data->clone_node_max = 1;
    }

    pe_rsc_trace(rsc, "Options for %s", rsc->id);
    pe_rsc_trace(rsc, "\tClone max: %d", clone_data->clone_max);
    pe_rsc_trace(rsc, "\tClone node max: %d", clone_data->clone_node_max);
    pe_rsc_trace(rsc, "\tClone is unique: %s",
                 is_set(rsc->flags, pe_rsc_unique) ? "true" : "false");

    clone_data->xml_obj_child = find_xml_node(xml_obj, XML_CIB_TAG_GROUP, FALSE);

    if (clone_data->xml_obj_child == NULL) {
        clone_data->xml_obj_child = find_xml_node(xml_obj, XML_CIB_TAG_RESOURCE, TRUE);
        for (a_child = __xml_first_child(xml_obj); a_child != NULL; a_child = __xml_next_element(a_child)) {
            if (crm_str_eq((const char *)a_child->name, XML_CIB_TAG_RESOURCE, TRUE)) {
                num_xml_children++;
            }
        }
    }

    if (clone_data->xml_obj_child == NULL) {
        crm_config_err("%s has nothing to clone", rsc->id);
        return FALSE;
    }

    for (a_child = __xml_first_child(xml_obj); a_child != NULL; a_child = __xml_next_element(a_child)) {
        if (crm_str_eq((const char *)a_child->name, type, TRUE)) {
            num_xml_children++;
        }
    }

    if (num_xml_children > 1) {
        crm_config_err("%s has too many children.  Only the first (%s) will be cloned.",
                       rsc->id, ID(clone_data->xml_obj_child));
    }

    /*
     * Make clones ever so slightly sticky by default
     *
     * This helps ensure clone instances are not shuffled around the cluster
     * for no benefit in situations when pre-allocation is not appropriate
     */
    if (g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_STICKINESS) == NULL) {
        add_hash_param(rsc->meta, XML_RSC_ATTR_STICKINESS, "1");
    }

    pe_rsc_trace(rsc, "\tClone is unique (fixed): %s",
                 is_set(rsc->flags, pe_rsc_unique) ? "true" : "false");
    clone_data->notify_confirm = is_set(rsc->flags, pe_rsc_notify);
    add_hash_param(rsc->meta, XML_RSC_ATTR_UNIQUE,
                   is_set(rsc->flags, pe_rsc_unique) ? XML_BOOLEAN_TRUE : XML_BOOLEAN_FALSE);

    for (lpc = 0; lpc < clone_data->clone_max; lpc++) {
        if (create_child_clone(rsc, lpc, data_set) == NULL) {
            return FALSE;
        }
    }

    if (clone_data->clone_max == 0) {
        /* create one so that unpack_find_resource() will hook up
         * any orphans up to the parent correctly
         */
        if (create_child_clone(rsc, -1, data_set) == NULL) {
            return FALSE;
        }
    }

    pe_rsc_trace(rsc, "Added %d children to resource %s...", clone_data->clone_max, rsc->id);
    return TRUE;
}
Esempio n. 11
0
int
main(int argc, char **argv)
{
    xmlNode *cib_object = NULL;
    xmlNode *status = NULL;
    int argerr = 0;
    int flag;
    int option_index = 0;

    pe_working_set_t data_set;
    cib_t *cib_conn = NULL;
    int rc = pcmk_ok;

    bool verbose = FALSE;
    gboolean xml_stdin = FALSE;
    const char *xml_tag = NULL;
    const char *xml_file = NULL;
    const char *xml_string = NULL;

    crm_log_cli_init("crm_verify");
    crm_set_options(NULL, "[modifiers] data_source", long_options,
                    "Check a (complete) confiuration for syntax and common conceptual errors."
                    "\n\nChecks the well-formedness of an XML configuration, its conformance to the configured DTD/schema and for the presence of common misconfigurations."
                    "\n\nIt reports two classes of problems, errors and warnings."
                    " Errors must be fixed before the cluster will work properly."
                    " However, it is left up to the administrator to decide if the warnings should also be fixed.");

    while (1) {
        flag = crm_get_option(argc, argv, &option_index);
        if (flag == -1)
            break;

        switch (flag) {
            case 'X':
                crm_trace("Option %c => %s", flag, optarg);
                xml_string = optarg;
                break;
            case 'x':
                crm_trace("Option %c => %s", flag, optarg);
                xml_file = optarg;
                break;
            case 'p':
                xml_stdin = TRUE;
                break;
            case 'S':
                cib_save = optarg;
                break;
            case 'V':
                verbose = TRUE;
                crm_bump_log_level(argc, argv);
                break;
            case 'L':
                USE_LIVE_CIB = TRUE;
                break;
            case '$':
            case '?':
                crm_help(flag, EX_OK);
                break;
            default:
                fprintf(stderr, "Option -%c is not yet supported\n", flag);
                ++argerr;
                break;
        }
    }

    if (optind < argc) {
        printf("non-option ARGV-elements: ");
        while (optind < argc) {
            printf("%s ", argv[optind++]);
        }
        printf("\n");
    }

    if (optind > argc) {
        ++argerr;
    }

    if (argerr) {
        crm_err("%d errors in option parsing", argerr);
        crm_help(flag, EX_USAGE);
    }

    crm_info("=#=#=#=#= Getting XML =#=#=#=#=");

    if (USE_LIVE_CIB) {
        cib_conn = cib_new();
        rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
    }

    if (USE_LIVE_CIB) {
        if (rc == pcmk_ok) {
            int options = cib_scope_local | cib_sync_call;

            crm_info("Reading XML from: live cluster");
            rc = cib_conn->cmds->query(cib_conn, NULL, &cib_object, options);
        }

        if (rc != pcmk_ok) {
            fprintf(stderr, "Live CIB query failed: %s\n", pcmk_strerror(rc));
            goto done;
        }
        if (cib_object == NULL) {
            fprintf(stderr, "Live CIB query failed: empty result\n");
            rc = -ENOMSG;
            goto done;
        }

    } else if (xml_file != NULL) {
        cib_object = filename2xml(xml_file);
        if (cib_object == NULL) {
            fprintf(stderr, "Couldn't parse input file: %s\n", xml_file);
            rc = -ENODATA;
            goto done;
        }

    } else if (xml_string != NULL) {
        cib_object = string2xml(xml_string);
        if (cib_object == NULL) {
            fprintf(stderr, "Couldn't parse input string: %s\n", xml_string);
            rc = -ENODATA;
            goto done;
        }
    } else if (xml_stdin) {
        cib_object = stdin2xml();
        if (cib_object == NULL) {
            fprintf(stderr, "Couldn't parse input from STDIN.\n");
            rc = -ENODATA;
            goto done;
        }

    } else {
        fprintf(stderr, "No configuration source specified."
                "  Use --help for usage information.\n");
        rc = -ENODATA;
        goto done;
    }

    xml_tag = crm_element_name(cib_object);
    if (safe_str_neq(xml_tag, XML_TAG_CIB)) {
        fprintf(stderr,
                "This tool can only check complete configurations (ie. those starting with <cib>).\n");
        rc = -EBADMSG;
        goto done;
    }

    if (cib_save != NULL) {
        write_xml_file(cib_object, cib_save, FALSE);
    }

    status = get_object_root(XML_CIB_TAG_STATUS, cib_object);
    if (status == NULL) {
        create_xml_node(cib_object, XML_CIB_TAG_STATUS);
    }

    if (validate_xml(cib_object, NULL, FALSE) == FALSE) {
        crm_config_err("CIB did not pass DTD/schema validation");
        free_xml(cib_object);
        cib_object = NULL;

    } else if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
        crm_config_error = TRUE;
        free_xml(cib_object);
        cib_object = NULL;
        fprintf(stderr, "The cluster will NOT be able to use this configuration.\n");
        fprintf(stderr, "Please manually update the configuration to conform to the %s syntax.\n",
                xml_latest_schema());
    }

    set_working_set_defaults(&data_set);
    if (cib_object == NULL) {
    } else if (USE_LIVE_CIB) {
        /* we will always have a status section and can do a full simulation */
        do_calculations(&data_set, cib_object, NULL);
        cleanup_alloc_calculations(&data_set);

    } else {
        data_set.now = crm_time_new(NULL);
        data_set.input = cib_object;
        stage0(&data_set);
        cleanup_alloc_calculations(&data_set);
    }

    if (crm_config_error) {
        fprintf(stderr, "Errors found during check: config not valid\n");
        if (verbose == FALSE) {
            fprintf(stderr, "  -V may provide more details\n");
        }
        rc = -pcmk_err_generic;

    } else if (crm_config_warning) {
        fprintf(stderr, "Warnings found during check: config may not be valid\n");
        if (verbose == FALSE) {
            fprintf(stderr, "  Use -V for more details\n");
        }
        rc = -pcmk_err_generic;
    }

    if (USE_LIVE_CIB && cib_conn) {
        cib_conn->cmds->signoff(cib_conn);
        cib_delete(cib_conn);
    }

  done:
    return rc;
}
Esempio n. 12
0
gboolean
group_unpack(resource_t * rsc, pe_working_set_t * data_set)
{
    resource_t *self = NULL;
    xmlNode *xml_obj = rsc->xml;
    xmlNode *xml_self = copy_xml(rsc->xml);
    xmlNode *xml_native_rsc = NULL;
    group_variant_data_t *group_data = NULL;
    const char *group_ordered = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_ORDERED);
    const char *group_colocated = g_hash_table_lookup(rsc->meta, "collocated");
    const char *clone_id = NULL;

    crm_debug_3("Processing resource %s...", rsc->id);

    crm_malloc0(group_data, sizeof(group_variant_data_t));
    group_data->num_children = 0;
    group_data->self = NULL;
    group_data->first_child = NULL;
    group_data->last_child = NULL;
    rsc->variant_opaque = group_data;

    group_data->ordered = TRUE;
    group_data->colocated = TRUE;

    if (group_ordered != NULL) {
        crm_str_to_boolean(group_ordered, &(group_data->ordered));
    }
    if (group_colocated != NULL) {
        crm_str_to_boolean(group_colocated, &(group_data->colocated));
    }

    /* this is a bit of a hack - but simplifies everything else */
    xmlNodeSetName(xml_self, ((const xmlChar *)XML_CIB_TAG_RESOURCE));
    if (common_unpack(xml_self, &self, NULL, data_set)) {
        group_data->self = self;
        self->restart_type = pe_restart_restart;

    } else {
        crm_log_xml_err(xml_self, "Couldnt unpack dummy child");
        return FALSE;
    }

    clone_id = crm_element_value(rsc->xml, XML_RSC_ATTR_INCARNATION);

    for (xml_native_rsc = __xml_first_child(xml_obj); xml_native_rsc != NULL;
         xml_native_rsc = __xml_next(xml_native_rsc)) {
        if (crm_str_eq((const char *)xml_native_rsc->name, XML_CIB_TAG_RESOURCE, TRUE)) {
            resource_t *new_rsc = NULL;

            crm_xml_add(xml_native_rsc, XML_RSC_ATTR_INCARNATION, clone_id);
            if (common_unpack(xml_native_rsc, &new_rsc, rsc, data_set) == FALSE) {
                pe_err("Failed unpacking resource %s", crm_element_value(xml_obj, XML_ATTR_ID));
                if (new_rsc != NULL && new_rsc->fns != NULL) {
                    new_rsc->fns->free(new_rsc);
                }
            }

            group_data->num_children++;
            rsc->children = g_list_append(rsc->children, new_rsc);

            if (group_data->first_child == NULL) {
                group_data->first_child = new_rsc;
            }
            group_data->last_child = new_rsc;
            print_resource(LOG_DEBUG_3, "Added", new_rsc, FALSE);
        }
    }

    if (group_data->num_children == 0) {
#if 0
        /* Bug #1287 */
        crm_config_err("Group %s did not have any children", rsc->id);
        return FALSE;
#else
        crm_config_warn("Group %s did not have any children", rsc->id);
        return TRUE;
#endif
    }

    crm_debug_3("Added %d children to resource %s...", group_data->num_children, rsc->id);

    return TRUE;
}