Example #1
0
static async_command_t *create_async_command(xmlNode *msg)
{
    async_command_t *cmd = NULL;
    xmlNode *op = get_xpath_object("//@"F_STONITH_ACTION, msg, LOG_ERR);
    const char *action = crm_element_value(op, F_STONITH_ACTION);

    CRM_CHECK(action != NULL, crm_log_xml_warn(msg, "NoAction"); return NULL);

    crm_log_xml_trace(msg, "Command");
    cmd = calloc(1, sizeof(async_command_t));
    crm_element_value_int(msg, F_STONITH_CALLID,   &(cmd->id));
    crm_element_value_int(msg, F_STONITH_CALLOPTS, &(cmd->options));
    crm_element_value_int(msg, F_STONITH_TIMEOUT,  &(cmd->timeout));

    cmd->origin = crm_element_value_copy(msg, F_ORIG);
    cmd->remote = crm_element_value_copy(msg, F_STONITH_REMOTE);
    cmd->client = crm_element_value_copy(msg, F_STONITH_CLIENTID);
    cmd->client_name = crm_element_value_copy(msg, F_STONITH_CLIENTNAME);
    cmd->op     = crm_element_value_copy(msg, F_STONITH_OPERATION);
    cmd->action = strdup(action);
    cmd->victim = crm_element_value_copy(op, F_STONITH_TARGET);
    cmd->mode   = crm_element_value_copy(op, F_STONITH_MODE);
    cmd->device = crm_element_value_copy(op, F_STONITH_DEVICE);
    cmd->done   = st_child_done;

    CRM_CHECK(cmd->op != NULL, crm_log_xml_warn(msg, "NoOp"); free_async_command(cmd); return NULL);
    CRM_CHECK(cmd->client != NULL, crm_log_xml_warn(msg, "NoClient"));

    cmd_list = g_list_append(cmd_list, cmd);
    return cmd;
}
Example #2
0
static enum crmd_fsa_input
handle_failcount_op(xmlNode * stored_msg)
{
    const char *rsc = NULL;
    xmlNode *xml_rsc = get_xpath_object("//" XML_CIB_TAG_RESOURCE, stored_msg, LOG_ERR);

    if (xml_rsc) {
        rsc = ID(xml_rsc);
    }

    if (rsc) {
        char *attr = NULL;

        crm_info("Removing failcount for %s", rsc);

        attr = crm_concat("fail-count", rsc, '-');
        update_attrd(NULL, attr, NULL, NULL);
        free(attr);

        attr = crm_concat("last-failure", rsc, '-');
        update_attrd(NULL, attr, NULL, NULL);
        free(attr);

        lrm_clear_last_failure(rsc);
    } else {
        crm_log_xml_warn(stored_msg, "invalid failcount op");
    }

    return I_NULL;
}
Example #3
0
int
stonith_fence_history(xmlNode * msg, xmlNode ** output)
{
    int rc = 0;
    const char *target = NULL;
    xmlNode *dev = get_xpath_object("//@" F_STONITH_TARGET, msg, LOG_TRACE);

    if (dev) {
        int options = 0;

        target = crm_element_value(dev, F_STONITH_TARGET);
        crm_element_value_int(msg, F_STONITH_CALLOPTS, &options);
        if (target && (options & st_opt_cs_nodeid)) {
            int nodeid = crm_atoi(target, NULL);
            crm_node_t *node = crm_get_peer(nodeid, NULL);

            if (node) {
                target = node->uname;
            }
        }
    }

    crm_trace("Looking for operations on %s in %p", target, remote_op_list);

    *output = create_xml_node(NULL, F_STONITH_HISTORY_LIST);
    if (remote_op_list) {
        GHashTableIter iter;
        remote_fencing_op_t *op = NULL;

        g_hash_table_iter_init(&iter, remote_op_list);
        while (g_hash_table_iter_next(&iter, NULL, (void **)&op)) {
            xmlNode *entry = NULL;

            if (target && strcmp(op->target, target) != 0) {
                continue;
            }

            rc = 0;
            crm_trace("Attaching op %s", op->id);
            entry = create_xml_node(*output, STONITH_OP_EXEC);
            crm_xml_add(entry, F_STONITH_TARGET, op->target);
            crm_xml_add(entry, F_STONITH_ACTION, op->action);
            crm_xml_add(entry, F_STONITH_ORIGIN, op->originator);
            crm_xml_add(entry, F_STONITH_DELEGATE, op->delegate);
            crm_xml_add(entry, F_STONITH_CLIENTNAME, op->client_name);
            crm_xml_add_int(entry, F_STONITH_DATE, op->completed);
            crm_xml_add_int(entry, F_STONITH_STATE, op->state);
        }
    }

    return rc;
}
Example #4
0
int
main(int argc, char ** argv)
{
    int flag;
    xmlNode *top = NULL;
    xmlNode *xml = NULL;
    const char *xml_file = NULL;
    const char *xpath = NULL;
    
    crm_log_init("atest", LOG_DEBUG, FALSE, TRUE, argc, argv);
    while (1) {
	flag = getopt(argc, argv, OPTARGS);
	if (flag == -1)
	    break;
	
	switch(flag) {
	    case 'X':
		xml_file = optarg;
		break;
	    case 'I':
		xpath = optarg;
		break;
	    case '?':
		/* usage("ptest", 0); */
		break;
	    default:
		printf("?? getopt returned character code 0%o ??\n", flag);
		break;
	}
    }

    top = filename2xml(xml_file);
    validate_xml(top, NULL, FALSE);

    if(xpath) {
	xml = get_xpath_object(xpath, top, LOG_ERR);	
    }
    
    if(xml) {
	char *buf = dump_xml_formatted(xml);
	printf("%s\n", buf);
	crm_free(buf);
    }

    free_xml(top);
    return 0;
}
Example #5
0
int
stonith_manual_ack(xmlNode * msg, remote_fencing_op_t * op)
{
    xmlNode *dev = get_xpath_object("//@" F_STONITH_TARGET, msg, LOG_ERR);

    op->state = st_done;
    op->completed = time(NULL);
    op->delegate = strdup("a human");

    crm_notice("Injecting manual confirmation that %s is safely off/down",
               crm_element_value(dev, F_STONITH_TARGET));

    remote_op_done(op, msg, pcmk_ok, FALSE);

    /* Replies are sent via done_cb->stonith_send_async_reply()->do_local_reply() */
    return -EINPROGRESS;
}
Example #6
0
static int stonith_manual_ack(xmlNode *msg, remote_fencing_op_t *op)
{
    async_command_t *cmd = create_async_command(msg);
    xmlNode *dev = get_xpath_object("//@"F_STONITH_TARGET, msg, LOG_ERR);

    if(cmd == NULL) {
        return -EINVAL;
    }

    cmd->device = strdup("manual_ack");
    cmd->remote = strdup(op->id);

    crm_notice("Injecting manual confirmation that %s is safely off/down",
               crm_element_value(dev, F_STONITH_TARGET));

    st_child_done(0, 0, cmd);
    return pcmk_ok;
}
Example #7
0
void
pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user)
{
#if ENABLE_ACL
    xml_private_t *p = NULL;

    if ((target == NULL) || (target->doc == NULL)
        || (target->doc->_private == NULL)) {
        return;
    }

    p = target->doc->_private;
    if (pcmk_acl_required(user) == FALSE) {
        crm_trace("no acls needed for '%s'", user);

    } else if (p->acls == NULL) {
        xmlNode *acls = get_xpath_object("//" XML_CIB_TAG_ACLS,
                                         source, LOG_TRACE);

        free(p->user);
        p->user = strdup(user);

        if (acls) {
            xmlNode *child = NULL;

            for (child = __xml_first_child(acls); child;
                 child = __xml_next(child)) {
                const char *tag = crm_element_name(child);

                if (!strcmp(tag, XML_ACL_TAG_USER)
                    || !strcmp(tag, XML_ACL_TAG_USERv1)) {
                    const char *id = crm_element_value(child, XML_ATTR_ID);

                    if (id && strcmp(id, user) == 0) {
                        crm_debug("Unpacking ACLs for %s", id);
                        p->acls = __xml_acl_parse_entry(acls, child, p->acls);
                    }
                }
            }
        }
    }
#endif
}
Example #8
0
static void
do_cib_updated(const char *event, xmlNode *msg)
{
    int rc = -1;
    xmlNode *diff = NULL;
	
    CRM_CHECK(msg != NULL, return);
    crm_element_value_int(msg, F_CIB_RC, &rc);	
    if(rc < cib_ok) {
	crm_debug_3("Filter rc=%d (%s)", rc, cib_error2string(rc));
	return;
    }

    diff = get_message_xml(msg, F_CIB_UPDATE_RESULT);
    if(get_xpath_object(
	   "//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_ADDED"//"XML_CIB_TAG_CRMCONFIG,
	   diff, LOG_DEBUG) != NULL) {
	mainloop_set_trigger(config_read);	    
    }
}
Example #9
0
void
container_expand(resource_t * rsc, pe_working_set_t * data_set)
{
    container_variant_data_t *container_data = NULL;

    CRM_CHECK(rsc != NULL, return);

    get_container_variant_data(container_data, rsc);

    if(container_data->child) {
        container_data->child->cmds->expand(container_data->child, data_set);
    }

    for (GListPtr gIter = container_data->tuples; gIter != NULL; gIter = gIter->next) {
        container_grouping_t *tuple = (container_grouping_t *)gIter->data;

        CRM_ASSERT(tuple);
        if (tuple->remote && tuple->docker && container_fix_remote_addr(tuple->remote)) {
            // REMOTE_CONTAINER_HACK: Allow remote nodes that start containers with pacemaker remote inside
            xmlNode *nvpair = get_xpath_object("//nvpair[@name='addr']", tuple->remote->xml, LOG_ERR);
            const char *calculated_addr = container_fix_remote_addr_in(tuple->remote, nvpair, "value");

            if (calculated_addr) {
                crm_trace("Fixed addr for %s on %s", tuple->remote->id, calculated_addr);
                g_hash_table_replace(tuple->remote->parameters, strdup("addr"), strdup(calculated_addr));
            } else {
                crm_err("Could not fix addr for %s", tuple->remote->id);
            }
        }
        if(tuple->ip) {
            tuple->ip->cmds->expand(tuple->ip, data_set);
        }
        if(tuple->docker) {
            tuple->docker->cmds->expand(tuple->docker, data_set);
        }
        if(tuple->remote) {
            tuple->remote->cmds->expand(tuple->remote, data_set);
        }
    }
}
Example #10
0
static enum crmd_fsa_input
handle_failcount_op(xmlNode * stored_msg)
{
    const char *rsc = NULL;
    const char *uname = NULL;
    gboolean is_remote_node = FALSE;
    xmlNode *xml_rsc = get_xpath_object("//" XML_CIB_TAG_RESOURCE, stored_msg, LOG_ERR);

    if (xml_rsc) {
        rsc = ID(xml_rsc);
    }

    uname = crm_element_value(stored_msg, XML_LRM_ATTR_TARGET);
    if (crm_element_value(stored_msg, XML_LRM_ATTR_ROUTER_NODE)) {
        is_remote_node = TRUE;
    }

    if (rsc) {
        char *attr = NULL;

        crm_info("Removing failcount for %s", rsc);

        attr = crm_concat("fail-count", rsc, '-');
        update_attrd(uname, attr, NULL, NULL, is_remote_node);
        free(attr);

        attr = crm_concat("last-failure", rsc, '-');
        update_attrd(uname, attr, NULL, NULL, is_remote_node);
        free(attr);

        lrm_clear_last_failure(rsc, uname);
    } else {
        crm_log_xml_warn(stored_msg, "invalid failcount op");
    }

    return I_NULL;
}
Example #11
0
/*!
 * \internal
 * \brief Create a new remote stonith op
 * \param client, he local stonith client id that initaited the operation
 * \param request, The request from the client that started the operation
 * \param peer, Is this operation owned by another stonith peer? Operations
 *        owned by other peers are stored on all the stonith nodes, but only the
 *        owner executes the operation.  All the nodes get the results to the operation
 *        once the owner finishes executing it.
 */
void *
create_remote_stonith_op(const char *client, xmlNode * request, gboolean peer)
{
    remote_fencing_op_t *op = NULL;
    xmlNode *dev = get_xpath_object("//@" F_STONITH_TARGET, request, LOG_TRACE);
    int call_options = 0;

    if (remote_op_list == NULL) {
        remote_op_list = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, free_remote_op);
    }

    /* If this operation is owned by another node, check to make
     * sure we haven't already created this operation. */
    if (peer && dev) {
        const char *op_id = crm_element_value(dev, F_STONITH_REMOTE_OP_ID);

        CRM_CHECK(op_id != NULL, return NULL);

        op = g_hash_table_lookup(remote_op_list, op_id);
        if (op) {
            crm_debug("%s already exists", op_id);
            return op;
        }
    }

    op = calloc(1, sizeof(remote_fencing_op_t));

    crm_element_value_int(request, F_STONITH_TIMEOUT, (int *)&(op->base_timeout));

    if (peer && dev) {
        op->id = crm_element_value_copy(dev, F_STONITH_REMOTE_OP_ID);
    } else {
        op->id = crm_generate_uuid();
    }

    g_hash_table_replace(remote_op_list, op->id, op);
    CRM_LOG_ASSERT(g_hash_table_lookup(remote_op_list, op->id) != NULL);
    crm_trace("Created %s", op->id);

    op->state = st_query;
    op->replies_expected = fencing_active_peers();
    op->action = crm_element_value_copy(dev, F_STONITH_ACTION);
    op->originator = crm_element_value_copy(dev, F_STONITH_ORIGIN);
    op->delegate = crm_element_value_copy(dev, F_STONITH_DELEGATE); /* May not be set */
    op->created = time(NULL);

    if (op->originator == NULL) {
        /* Local or relayed request */
        op->originator = strdup(stonith_our_uname);
    }

    CRM_LOG_ASSERT(client != NULL);
    if (client) {
        op->client_id = strdup(client);
    }

    op->client_name = crm_element_value_copy(request, F_STONITH_CLIENTNAME);

    op->target = crm_element_value_copy(dev, F_STONITH_TARGET);
    op->request = copy_xml(request);    /* TODO: Figure out how to avoid this */
    crm_element_value_int(request, F_STONITH_CALLOPTS, &call_options);
    op->call_options = call_options;
    
    crm_element_value_int(request, F_STONITH_CALLID, (int *)&(op->client_callid));

    crm_trace("%s new stonith op: %s - %s of %s for %s",
              (peer
               && dev) ? "Recorded" : "Generated", op->id, op->action, op->target, op->client_name);

    if (op->call_options & st_opt_cs_nodeid) {
        int nodeid = crm_atoi(op->target, NULL);
        crm_node_t *node = crm_get_peer(nodeid, NULL);

        /* Ensure the conversion only happens once */
        op->call_options &= ~st_opt_cs_nodeid;

        if (node && node->uname) {
            free(op->target);
            op->target = strdup(node->uname);
        } else {
            crm_warn("Could not expand nodeid '%s' into a host name (%p)", op->target, node);
        }
    }

    /* check to see if this is a duplicate operation of another in-flight operation */
    merge_duplicates(op);

    return op;
}
Example #12
0
static void
tengine_stonith_notify(stonith_t * st, const char *event, xmlNode * msg)
{
    int rc = -99;
    const char *origin = NULL;
    const char *target = NULL;
    const char *executioner = NULL;
    xmlNode *action = get_xpath_object("//st-data", msg, LOG_ERR);

    if (action == NULL) {
        crm_log_xml(LOG_ERR, "Notify data not found", msg);
        return;
    }

    crm_log_xml(LOG_DEBUG, "stonith_notify", msg);
    crm_element_value_int(msg, F_STONITH_RC, &rc);
    origin = crm_element_value(action, F_STONITH_ORIGIN);
    target = crm_element_value(action, F_STONITH_TARGET);
    executioner = crm_element_value(action, F_STONITH_DELEGATE);

    if (rc == stonith_ok && crm_str_eq(target, fsa_our_uname, TRUE)) {
        crm_err("We were alegedly just fenced by %s for %s!", executioner, origin);
        register_fsa_error_adv(C_FSA_INTERNAL, I_ERROR, NULL, NULL, __FUNCTION__);

    } else if (rc == stonith_ok) {
        crm_info("Peer %s was terminated (%s) by %s for %s (ref=%s): %s",
                 target,
                 crm_element_value(action, F_STONITH_OPERATION),
                 executioner, origin,
                 crm_element_value(action, F_STONITH_REMOTE), stonith_error2string(rc));
    } else {
        crm_err("Peer %s could not be terminated (%s) by %s for %s (ref=%s): %s",
                target,
                crm_element_value(action, F_STONITH_OPERATION),
                executioner ? executioner : "<anyone>", origin,
                crm_element_value(action, F_STONITH_REMOTE), stonith_error2string(rc));
    }

#ifdef SUPPORT_CMAN
    if (rc == stonith_ok && is_cman_cluster()) {
        int local_rc = 0;
        int confirm = 0;
        char *target_copy = crm_strdup(target);

        /* In case fenced hasn't noticed yet */
        local_rc = fenced_external(target_copy);
        if (local_rc != 0) {
            crm_err("Could not notify CMAN that '%s' is now fenced: %d", target, local_rc);
        } else {
            crm_notice("Notified CMAN that '%s' is now fenced", target);
        }

        /* In case fenced is already trying to shoot it */
        confirm = open("/var/run/cluster/fenced_override", O_NONBLOCK|O_WRONLY);
        if (confirm) {
            int len = strlen(target_copy);

            errno = 0;
            local_rc = write(confirm, target_copy, len);
            write(confirm, "\n", 1);

            if(errno == EBADF) {
                crm_trace("CMAN not expecting %s to be fenced (yet)", target);

            } else if (local_rc < len) {
                crm_perror(LOG_ERR, "Confirmation of CMAN fencing event for '%s' failed: %d", target, local_rc);

            } else {
                fsync(confirm);
                crm_notice("Confirmed CMAN fencing event for '%s'", target);
            }
            close(confirm);
        }
    }
#endif

    if (rc == stonith_ok && safe_str_eq(target, origin)) {
        if (fsa_our_dc == NULL || safe_str_eq(fsa_our_dc, target)) {
            crm_notice("Target was our leader %s (recorded: %s)",
                       target, fsa_our_dc ? fsa_our_dc : "<unset>");
            /* Given the CIB resyncing that occurs around elections,
             * have one node update the CIB now and, if the new DC is different,
             * have them do so too after the election
             */
            if (safe_str_eq(executioner, fsa_our_uname)) {
                const char *uuid = get_uuid(target);

                send_stonith_update(NULL, target, uuid);
            } else {
                stonith_cleanup_list = g_list_append(stonith_cleanup_list, crm_strdup(target));
            }
        }
    }
}
Example #13
0
int process_remote_stonith_query(xmlNode *msg) 
{
    int devices = 0;
    const char *id = NULL;
    const char *host = NULL;
    remote_fencing_op_t *op = NULL;
    st_query_result_t *result = NULL;
    xmlNode *dev = get_xpath_object("//@"F_STONITH_REMOTE, msg, LOG_ERR);
    xmlNode *child = NULL;

    CRM_CHECK(dev != NULL, return -EPROTO);

    id = crm_element_value(dev, F_STONITH_REMOTE);
    CRM_CHECK(id != NULL, return -EPROTO);

    dev = get_xpath_object("//@st-available-devices", msg, LOG_ERR);
    CRM_CHECK(dev != NULL, return -EPROTO);
    crm_element_value_int(dev, "st-available-devices", &devices);

    op = g_hash_table_lookup(remote_op_list, id);
    if(op == NULL) {
        crm_debug("Unknown or expired remote op: %s", id);
        return -EOPNOTSUPP;
    }

    op->replies++;
    host = crm_element_value(msg, F_ORIG);

    if(devices <= 0) {
        /* If we're doing 'known' then we might need to fire anyway */
        crm_trace("Query result from %s (%d devices)", host, devices);
        return pcmk_ok;

    } else if(op->call_options & st_opt_allow_suicide) {
        crm_trace("Allowing %s to potentialy fence itself", op->target);

    } else if(safe_str_eq(host, op->target)) {
        crm_info("Ignoring reply from %s, hosts are not permitted to commit suicide", op->target);
        return pcmk_ok;
    }

    crm_debug("Query result from %s (%d devices)", host, devices);
    result = calloc(1, sizeof(st_query_result_t));
    result->host = strdup(host);
    result->devices = devices;

    for (child = __xml_first_child(dev); child != NULL; child = __xml_next(child)) {
        const char *device = ID(child);
        if(device) {
            result->device_list = g_list_prepend(result->device_list, strdup(device));
        }
    }

    CRM_CHECK(devices == g_list_length(result->device_list),
              crm_err("Mis-match: Query claimed to have %d devices but %d found", devices, g_list_length(result->device_list)));

    op->query_results = g_list_insert_sorted(op->query_results, result, sort_peers);

    if(op->state == st_query && is_set(op->call_options, st_opt_all_replies) == FALSE) {
        call_remote_stonith(op, result);

    } else if(op->state == st_done) {
        crm_info("Discarding query result from %s (%d devices): Operation is in state %d",
                 result->host, result->devices, op->state);
    }

    return pcmk_ok;
}
Example #14
0
void *create_remote_stonith_op(const char *client, xmlNode *request, gboolean peer)
{
    remote_fencing_op_t *op = NULL;
    xmlNode *dev = get_xpath_object("//@"F_STONITH_TARGET, request, LOG_TRACE);

    if(remote_op_list == NULL) {
        remote_op_list = g_hash_table_new_full(
        crm_str_hash, g_str_equal, NULL, free_remote_op);
    }

    if(peer && dev) {
        const char *peer_id = crm_element_value(dev, F_STONITH_REMOTE);
        CRM_CHECK(peer_id != NULL, return NULL);

        op = g_hash_table_lookup(remote_op_list, peer_id);
        if(op) {
            crm_debug("%s already exists", peer_id);
            return op;
        }
    }

    op = calloc(1, sizeof(remote_fencing_op_t));
    crm_element_value_int(request, F_STONITH_TIMEOUT, (int*)&(op->base_timeout));

    if(peer && dev) {
        op->id = crm_element_value_copy(dev, F_STONITH_REMOTE);
        crm_trace("Recorded new stonith op: %s", op->id);
    } else {
        op->id = crm_generate_uuid();
        crm_trace("Generated new stonith op: %s", op->id);
    }

    g_hash_table_replace(remote_op_list, op->id, op);
    CRM_LOG_ASSERT(g_hash_table_lookup(remote_op_list, op->id) != NULL);

    op->state = st_query;
    op->action = crm_element_value_copy(dev, F_STONITH_ACTION);
    op->originator = crm_element_value_copy(dev, F_STONITH_OWNER);

    if(op->originator == NULL) {
        /* Local request */
        op->originator = strdup(stonith_our_uname);
    }

    if(client) {
        op->client_id = strdup(client);
    }

    op->client_name = crm_element_value_copy(request, F_STONITH_CLIENTNAME);

    op->target = crm_element_value_copy(dev, F_STONITH_TARGET);
    op->request = copy_xml(request); /* TODO: Figure out how to avoid this */
    crm_element_value_int(request, F_STONITH_CALLOPTS, (int*)&(op->call_options));

    if(op->call_options & st_opt_cs_nodeid) {
        int nodeid = crm_atoi(op->target, NULL);
        crm_node_t *node = crm_get_peer(nodeid, NULL);

        /* Ensure the conversion only happens once */
        op->call_options &= ~st_opt_cs_nodeid;

        if(node) {
            free(op->target);
            op->target = strdup(node->uname);
        }
    }

    if(stonith_topology_next(op) != pcmk_ok) {
        op->state = st_failed;
    }
    return op;
}
Example #15
0
int
process_remote_stonith_query(xmlNode * msg)
{
    int devices = 0;
    gboolean host_is_target = FALSE;
    const char *id = NULL;
    const char *host = NULL;
    remote_fencing_op_t *op = NULL;
    st_query_result_t *result = NULL;
    uint32_t active = fencing_active_peers();
    xmlNode *dev = get_xpath_object("//@" F_STONITH_REMOTE_OP_ID, msg, LOG_ERR);
    xmlNode *child = NULL;

    CRM_CHECK(dev != NULL, return -EPROTO);

    id = crm_element_value(dev, F_STONITH_REMOTE_OP_ID);
    CRM_CHECK(id != NULL, return -EPROTO);

    dev = get_xpath_object("//@st-available-devices", msg, LOG_ERR);
    CRM_CHECK(dev != NULL, return -EPROTO);
    crm_element_value_int(dev, "st-available-devices", &devices);

    op = g_hash_table_lookup(remote_op_list, id);
    if (op == NULL) {
        crm_debug("Unknown or expired remote op: %s", id);
        return -EOPNOTSUPP;
    }

    op->replies++;
    host = crm_element_value(msg, F_ORIG);
    host_is_target = safe_str_eq(host, op->target);

    if (devices <= 0) {
        /* If we're doing 'known' then we might need to fire anyway */
        crm_trace("Query result from %s (%d devices)", host, devices);
        if(op->state == st_query && (op->replies >= op->replies_expected || op->replies >= active)) {
            crm_info("All queries have arrived, continuing (%d, %d, %d) ", op->replies_expected, active, op->replies);
            call_remote_stonith(op, NULL);
        }
        return pcmk_ok;

    } else if (host_is_target) {
        if (op->call_options & st_opt_allow_suicide) {
            crm_trace("Allowing %s to potentialy fence itself", op->target);
        } else {
            crm_info("Ignoring reply from %s, hosts are not permitted to commit suicide",
                     op->target);
            return pcmk_ok;
        }
    }

    crm_info("Query result %d of %d from %s (%d devices)", op->replies, op->replies_expected, host, devices);
    result = calloc(1, sizeof(st_query_result_t));
    result->host = strdup(host);
    result->devices = devices;
    result->custom_action_timeouts = g_hash_table_new_full(crm_str_hash, g_str_equal, free, NULL);
    result->verified_devices = g_hash_table_new_full(crm_str_hash, g_str_equal, free, NULL);

    for (child = __xml_first_child(dev); child != NULL; child = __xml_next(child)) {
        const char *device = ID(child);
        int action_timeout = 0;
        int verified = 0;

        if (device) {
            result->device_list = g_list_prepend(result->device_list, strdup(device));
            crm_element_value_int(child, F_STONITH_ACTION_TIMEOUT, &action_timeout);
            crm_element_value_int(child, F_STONITH_DEVICE_VERIFIED, &verified);
            if (action_timeout) {
                crm_trace("Peer %s with device %s returned action timeout %d",
                          result->host, device, action_timeout);
                g_hash_table_insert(result->custom_action_timeouts,
                                    strdup(device), GINT_TO_POINTER(action_timeout));
            }
            if (verified) {
                crm_trace("Peer %s has confirmed a verified device %s", result->host, device);
                g_hash_table_insert(result->verified_devices,
                                    strdup(device), GINT_TO_POINTER(verified));
            }
        }
    }

    CRM_CHECK(devices == g_list_length(result->device_list),
              crm_err("Mis-match: Query claimed to have %d devices but %d found", devices,
                      g_list_length(result->device_list)));

    op->query_results = g_list_insert_sorted(op->query_results, result, sort_peers);

    if (is_set(op->call_options, st_opt_topology)) {
        /* If we start the fencing before all the topology results are in,
         * it is possible fencing levels will be skipped because of the missing
         * query results. */
        if (op->state == st_query && all_topology_devices_found(op)) {
            /* All the query results are in for the topology, start the fencing ops. */
            crm_trace("All topology devices found");
            call_remote_stonith(op, result);

        } else if(op->state == st_query && (op->replies >= op->replies_expected || op->replies >= active)) {
            crm_info("All topology queries have arrived, continuing (%d, %d, %d) ", op->replies_expected, active, op->replies);
            call_remote_stonith(op, NULL);
        }

    } else if (op->state == st_query) {
        /* We have a result for a non-topology fencing op that looks promising,
         * go ahead and start fencing before query timeout */
        if (host_is_target == FALSE && g_hash_table_size(result->verified_devices)) {
            /* we have a verified device living on a peer that is not the target */
            crm_trace("Found %d verified devices", g_hash_table_size(result->verified_devices));
            call_remote_stonith(op, result);

        } else if (safe_str_eq(op->action, "on")) {
            crm_trace("Unfencing %s", op->target);
            call_remote_stonith(op, result);

        } else if(op->replies >= op->replies_expected || op->replies >= active) {
            crm_info("All queries have arrived, continuing (%d, %d, %d) ", op->replies_expected, active, op->replies);
            call_remote_stonith(op, NULL);

        } else {
            crm_trace("Waiting for more peer results before launching fencing operation");
        }

    } else if (op->state == st_done) {
        crm_info("Discarding query result from %s (%d devices): Operation is in state %d",
                 result->host, result->devices, op->state);
    }

    return pcmk_ok;
}
Example #16
0
int
process_remote_stonith_exec(xmlNode * msg)
{
    int rc = 0;
    const char *id = NULL;
    const char *device = NULL;
    remote_fencing_op_t *op = NULL;
    xmlNode *dev = get_xpath_object("//@" F_STONITH_REMOTE_OP_ID, msg, LOG_ERR);

    CRM_CHECK(dev != NULL, return -EPROTO);

    id = crm_element_value(dev, F_STONITH_REMOTE_OP_ID);
    CRM_CHECK(id != NULL, return -EPROTO);

    dev = get_xpath_object("//@" F_STONITH_RC, msg, LOG_ERR);
    CRM_CHECK(dev != NULL, return -EPROTO);

    crm_element_value_int(dev, F_STONITH_RC, &rc);

    device = crm_element_value(dev, F_STONITH_DEVICE);

    if (remote_op_list) {
        op = g_hash_table_lookup(remote_op_list, id);
    }

    if (op == NULL && rc == pcmk_ok) {
        /* Record successful fencing operations */
        const char *client_id = crm_element_value(dev, F_STONITH_CLIENTID);

        op = create_remote_stonith_op(client_id, dev, TRUE);
    }

    if (op == NULL) {
        /* Could be for an event that began before we started */
        /* TODO: Record the op for later querying */
        crm_info("Unknown or expired remote op: %s", id);
        return -EOPNOTSUPP;
    }

    if (op->devices && device && safe_str_neq(op->devices->data, device)) {
        crm_err
            ("Received outdated reply for device %s (instead of %s) to %s node %s. Operation already timed out at remote level.",
             device, op->devices->data, op->action, op->target);
        return rc;
    }

    if (safe_str_eq(crm_element_value(msg, F_SUBTYPE), "broadcast")) {
        crm_debug("Marking call to %s for %s on behalf of %s@%s.%.8s: %s (%d)",
                  op->action, op->target, op->client_name, op->id, op->originator,
                  pcmk_strerror(rc), rc);
        if (rc == pcmk_ok) {
            op->state = st_done;
        } else {
            op->state = st_failed;
        }
        remote_op_done(op, msg, rc, FALSE);
        return pcmk_ok;
    } else if (safe_str_neq(op->originator, stonith_our_uname)) {
        /* If this isn't a remote level broadcast, and we are not the
         * originator of the operation, we should not be receiving this msg. */
        crm_err
            ("%s received non-broadcast fencing result for operation it does not own (device %s targeting %s)",
             stonith_our_uname, device, op->target);
        return rc;
    }

    if (is_set(op->call_options, st_opt_topology)) {
        const char *device = crm_element_value(msg, F_STONITH_DEVICE);

        crm_notice("Call to %s for %s on behalf of %s@%s: %s (%d)",
                   device, op->target, op->client_name, op->originator,
                   pcmk_strerror(rc), rc);

        /* We own the op, and it is complete. broadcast the result to all nodes
         * and notify our local clients. */
        if (op->state == st_done) {
            remote_op_done(op, msg, rc, FALSE);
            return rc;
        }

        /* An operation completed succesfully but has not yet been marked as done.
         * Continue the topology if more devices exist at the current level, otherwise
         * mark as done. */
        if (rc == pcmk_ok) {
            if (op->devices) {
                /* Success, are there any more? */
                op->devices = op->devices->next;
            }
            /* if no more devices at this fencing level, we are done,
             * else we need to contine with executing the next device in the list */
            if (op->devices == NULL) {
                crm_trace("Marking complex fencing op for %s as complete", op->target);
                op->state = st_done;
                remote_op_done(op, msg, rc, FALSE);
                return rc;
            }
        } else {
            /* This device failed, time to try another topology level. If no other
             * levels are available, mark this operation as failed and report results. */
            if (stonith_topology_next(op) != pcmk_ok) {
                op->state = st_failed;
                remote_op_done(op, msg, rc, FALSE);
                return rc;
            }
        }
    } else if (rc == pcmk_ok && op->devices == NULL) {
        crm_trace("All done for %s", op->target);

        op->state = st_done;
        remote_op_done(op, msg, rc, FALSE);
        return rc;
    }

    /* Retry on failure or execute the rest of the topology */
    crm_trace("Next for %s on behalf of %s@%s (rc was %d)", op->target, op->originator,
              op->client_name, rc);
    call_remote_stonith(op, NULL);
    return rc;
}
Example #17
0
int process_remote_stonith_exec(xmlNode *msg) 
{
    int rc = 0;
    const char *id = NULL;
    remote_fencing_op_t *op = NULL;
    xmlNode *dev = get_xpath_object("//@"F_STONITH_REMOTE, msg, LOG_ERR);

    CRM_CHECK(dev != NULL, return -EPROTO);

    id = crm_element_value(dev, F_STONITH_REMOTE);
    CRM_CHECK(id != NULL, return -EPROTO);

    dev = get_xpath_object("//@"F_STONITH_RC, msg, LOG_ERR);
    CRM_CHECK(dev != NULL, return -EPROTO);

    crm_element_value_int(dev, F_STONITH_RC, &rc);

    if(remote_op_list) {
        op = g_hash_table_lookup(remote_op_list, id);
    }

    if(op == NULL && rc == pcmk_ok) {
        /* Record successful fencing operations */
        const char *client_id = crm_element_value(msg, F_STONITH_CLIENTID);

        op = create_remote_stonith_op(client_id, msg, TRUE);
    }

    if(op == NULL) {
        /* Could be for an event that began before we started */
        /* TODO: Record the op for later querying */
        crm_info("Unknown or expired remote op: %s", id);
        return -EOPNOTSUPP;
    }

    if(is_set(op->call_options, st_opt_topology)) {
        const char *device = crm_element_value(msg, F_STONITH_DEVICE);

        crm_notice("Call to %s for %s on behalf of %s: %s (%d)", device, op->target, op->originator, rc == pcmk_ok?"passed":"failed", rc);
        if(safe_str_eq(op->originator, stonith_our_uname)) {

            if(op->state == st_done) {
                remote_op_done(op, msg, rc);
                return rc;

            } else if(rc == pcmk_ok && op->devices) {
                /* Success, are there any more? */
                op->devices = op->devices->next;
            }

            if(op->devices == NULL) {
                crm_trace("Broadcasting completion of complex fencing op for %s", op->target);
                send_cluster_message(NULL, crm_msg_stonith_ng, msg, FALSE);
                op->state = st_done;
                return rc;
            }

        } else {
            op->state = st_done;
            remote_op_done(op, msg, rc);
        }

    } else if(rc == pcmk_ok && op->devices == NULL) {
        crm_trace("All done for %s", op->target);

        op->state = st_done;
        remote_op_done(op, msg, rc);
        return rc;
    }

    /* Retry on failure or execute the rest of the topology */
    crm_trace("Next for %s (rc was %d)", op->target, rc);
    call_remote_stonith(op, NULL);
    return rc;
}
Example #18
0
void
te_update_diff(const char *event, xmlNode *msg)
{
	int rc = -1;
	const char *op = NULL;

	xmlNode *diff = NULL;
	xmlNode *cib_top = NULL;
	xmlXPathObject *xpathObj = NULL;

	int diff_add_updates     = 0;
	int diff_add_epoch       = 0;
	int diff_add_admin_epoch = 0;

	int diff_del_updates     = 0;
	int diff_del_epoch       = 0;
	int diff_del_admin_epoch = 0;
	
	CRM_CHECK(msg != NULL, return);
	crm_element_value_int(msg, F_CIB_RC, &rc);	

	if(transition_graph == NULL) {
	    crm_debug_3("No graph");
	    return;

	} else if(rc < cib_ok) {
	    crm_debug_3("Filter rc=%d (%s)", rc, cib_error2string(rc));
	    return;

	} else if(transition_graph->complete == TRUE
		  && fsa_state != S_IDLE
		  && fsa_state != S_TRANSITION_ENGINE
		  && fsa_state != S_POLICY_ENGINE) {
	    crm_debug_2("Filter state=%s, complete=%d", fsa_state2string(fsa_state), transition_graph->complete);
	    return;
	} 	

	op = crm_element_value(msg, F_CIB_OPERATION);
	diff = get_message_xml(msg, F_CIB_UPDATE_RESULT);

	cib_diff_version_details(
		diff,
		&diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates, 
		&diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
	
	crm_debug("Processing diff (%s): %d.%d.%d -> %d.%d.%d (%s)", op,
		  diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
		  diff_add_admin_epoch,diff_add_epoch,diff_add_updates,
		  fsa_state2string(fsa_state));
	log_cib_diff(LOG_DEBUG_2, diff, op);

	/* Process anything that was added */
	cib_top = get_xpath_object("//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_ADDED"//"XML_TAG_CIB, diff, LOG_ERR);
	if(need_abort(cib_top)) {
	    goto bail; /* configuration changed */
	}

	/* Process anything that was removed */
	cib_top = get_xpath_object("//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_REMOVED"//"XML_TAG_CIB, diff, LOG_ERR);
	if(need_abort(cib_top)) {
	    goto bail; /* configuration changed */
	}

	/* Transient Attributes - Added/Updated */
	xpathObj = xpath_search(diff,"//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_ADDED"//"XML_TAG_TRANSIENT_NODEATTRS"//"XML_CIB_TAG_NVPAIR);
	if(xpathObj && xpathObj->nodesetval->nodeNr > 0) {
	    int lpc;
	    for(lpc = 0; lpc < xpathObj->nodesetval->nodeNr; lpc++) {
		xmlNode *attr = getXpathResult(xpathObj, lpc);
		const char *name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
		const char *value = NULL;
		
		if(safe_str_eq(CRM_OP_PROBED, name)) {
		    value = crm_element_value(attr, XML_NVPAIR_ATTR_VALUE);
		}

		if(crm_is_true(value) == FALSE) {
		    abort_transition(INFINITY, tg_restart, "Transient attribute: update", attr);
		    crm_log_xml_debug_2(attr, "Abort");
		    goto bail;
		}
	    }

	} else if(xpathObj) {
	    xmlXPathFreeObject(xpathObj);
	}
	
	/* Transient Attributes - Removed */
	xpathObj = xpath_search(diff,"//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_REMOVED"//"XML_TAG_TRANSIENT_NODEATTRS);
	if(xpathObj && xpathObj->nodesetval->nodeNr > 0) {
	    xmlNode *aborted = getXpathResult(xpathObj, 0);
	    abort_transition(INFINITY, tg_restart, "Transient attribute: removal", aborted);
	    goto bail;

	} else if(xpathObj) {
	    xmlXPathFreeObject(xpathObj);
	}

	/* Check for node state updates... possibly from a shutdown we requested */
	xpathObj = xpath_search(diff, "//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_ADDED"//"XML_CIB_TAG_STATE);
	if(xpathObj) {
	    int lpc = 0, max = xpathObj->nodesetval->nodeNr;
	    for(lpc = 0; lpc < max; lpc++) {
		xmlNode *node = getXpathResult(xpathObj, lpc);
		const char *event_node = crm_element_value(node, XML_ATTR_ID);
		const char *ccm_state  = crm_element_value(node, XML_CIB_ATTR_INCCM);
		const char *ha_state   = crm_element_value(node, XML_CIB_ATTR_HASTATE);
		const char *shutdown_s = crm_element_value(node, XML_CIB_ATTR_SHUTDOWN);
		const char *crmd_state = crm_element_value(node, XML_CIB_ATTR_CRMDSTATE);

		if(safe_str_eq(ccm_state, XML_BOOLEAN_FALSE)
		   || safe_str_eq(ha_state, DEADSTATUS)
		   || safe_str_eq(crmd_state, CRMD_JOINSTATE_DOWN)) {
		    crm_action_t *shutdown = match_down_event(0, event_node, NULL);
		    
		    if(shutdown != NULL) {
			const char *task = crm_element_value(shutdown->xml, XML_LRM_ATTR_TASK);
			if(safe_str_neq(task, CRM_OP_FENCE)) {
			    /* Wait for stonithd to tell us it is complete via tengine_stonith_callback() */
			    update_graph(transition_graph, shutdown);
			    trigger_graph();
			}
			
		    } else {
			crm_info("Stonith/shutdown of %s not matched", event_node);
			abort_transition(INFINITY, tg_restart, "Node failure", node);
		    }			
		    fail_incompletable_actions(transition_graph, event_node);
		}
	 
		if(shutdown_s) {
		    int shutdown = crm_parse_int(shutdown_s, NULL);
		    if(shutdown > 0) {
			crm_info("Aborting on "XML_CIB_ATTR_SHUTDOWN" attribute for %s", event_node);
			abort_transition(INFINITY, tg_restart, "Shutdown request", node);
		    }
		}
	    }
	    xmlXPathFreeObject(xpathObj);
	}

	/*
	 * Check for and fast-track the processing of LRM refreshes
	 * In large clusters this can result in _huge_ speedups
	 *
	 * Unfortunately we can only do so when there are no pending actions
	 * Otherwise we could miss updates we're waiting for and stall 
	 *
	 */
	xpathObj = NULL;
	if(transition_graph->pending == 0) {
	    xpathObj = xpath_search(diff, "//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_ADDED"//"XML_LRM_TAG_RESOURCE);
	}
	
	if(xpathObj) {
	    int updates = xpathObj->nodesetval->nodeNr;
	    if(updates > 1) {
		/* Updates by, or in response to, TE actions will never contain updates
		 * for more than one resource at a time
		 */
		crm_info("Detected LRM refresh - %d resources updated: Skipping all resource events", updates);
		abort_transition(INFINITY, tg_restart, "LRM Refresh", diff);
		goto bail;
	    }
	    xmlXPathFreeObject(xpathObj);
	}

	/* Process operation updates */
	xpathObj = xpath_search(diff, "//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_ADDED"//"XML_LRM_TAG_RSC_OP);
	if(xpathObj) {
	    process_resource_updates(xpathObj);
	    xmlXPathFreeObject(xpathObj);
	}
	
	/* Detect deleted (as opposed to replaced or added) actions - eg. crm_resource -C */ 
	xpathObj = xpath_search(diff, "//"XML_TAG_DIFF_REMOVED"//"XML_LRM_TAG_RSC_OP);
	if(xpathObj) {
	    int lpc = 0, max = xpathObj->nodesetval->nodeNr;
	    
	    for(lpc = 0; lpc < max; lpc++) {
		int max = 0;
		const char *op_id = NULL;
		char *rsc_op_xpath = NULL;
		xmlXPathObject *op_match = NULL;
		xmlNode *match = getXpathResult(xpathObj, lpc);
		CRM_CHECK(match != NULL, continue);

		op_id = ID(match);

		max = strlen(rsc_op_template) + strlen(op_id) + 1;
		crm_malloc0(rsc_op_xpath, max);
		snprintf(rsc_op_xpath, max, rsc_op_template, op_id);
		
		op_match = xpath_search(diff, rsc_op_xpath);
		if(op_match == NULL || op_match->nodesetval->nodeNr == 0) {
		    /* Prevent false positives by matching cancelations too */
		    const char *node = get_node_id(match);
		    crm_action_t *cancelled = get_cancel_action(op_id, node);

		    if(cancelled == NULL) {
			crm_debug("No match for deleted action %s (%s on %s)", rsc_op_xpath, op_id, node);
			abort_transition(INFINITY, tg_restart, "Resource op removal", match);
			if(op_match) {
			    xmlXPathFreeObject(op_match);
			}
			crm_free(rsc_op_xpath);
			goto bail;

		    } else {
			crm_debug("Deleted lrm_rsc_op %s on %s was for graph event %d",
				  op_id, node, cancelled->id);
		    }
		}

		if(op_match) {
		    xmlXPathFreeObject(op_match);
		}
		crm_free(rsc_op_xpath);
	    }
	}

  bail:
	if(xpathObj) {
	    xmlXPathFreeObject(xpathObj);
	}
}
Example #19
0
/*!
 * \internal
 * \brief Handle fence-history messages (either from API or coming in as
 *        broadcasts
 *
 * \param[in] msg       Request message
 * \param[in] output    In case of a request from the API used to craft
 *                      a reply from
 * \param[in] remote_peer
 * \param[in] options   call-options from the request
 *
 * \return always success as there is actully nothing that can go really wrong
 */
int
stonith_fence_history(xmlNode *msg, xmlNode **output,
                      const char *remote_peer, int options)
{
    int rc = 0;
    const char *target = NULL;
    xmlNode *dev = get_xpath_object("//@" F_STONITH_TARGET, msg, LOG_TRACE);
    xmlNode *out_history = NULL;

    if (dev) {
        target = crm_element_value(dev, F_STONITH_TARGET);
        if (target && (options & st_opt_cs_nodeid)) {
            int nodeid = crm_atoi(target, NULL);
            crm_node_t *node = crm_find_known_peer_full(nodeid, NULL, CRM_GET_PEER_ANY);

            if (node) {
                target = node->uname;
            }
        }
    }

    if (options & st_opt_cleanup) {
        crm_trace("Cleaning up operations on %s in %p", target,
                  stonith_remote_op_list);

        stonith_fence_history_cleanup(target,
            crm_element_value(msg, F_STONITH_CALLID) != NULL);
    } else if (options & st_opt_broadcast) {
        if (crm_element_value(msg, F_STONITH_CALLID)) {
            /* this is coming from the stonith-API
            *
            * craft a broadcast with node's history
            * so that every node can merge and broadcast
            * what it has on top
            */
            out_history = stonith_local_history_diff(NULL, TRUE, NULL);
            crm_trace("Broadcasting history to peers");
            stonith_send_broadcast_history(out_history,
                                        st_opt_broadcast | st_opt_discard_reply,
                                        NULL);
        } else if (remote_peer &&
                   !safe_str_eq(remote_peer, stonith_our_uname)) {
            xmlNode *history =
                get_xpath_object("//" F_STONITH_HISTORY_LIST, msg, LOG_TRACE);
            GHashTable *received_history =
                history?stonith_xml_history_to_list(history):NULL;

            /* either a broadcast created directly upon stonith-API request
            * or a diff as response to such a thing
            *
            * in both cases it may have a history or not
            * if we have differential data
            * merge in what we've received and stop
            * otherwise broadcast what we have on top
            * marking as differential and merge in afterwards
            */
            if (!history ||
                !crm_is_true(crm_element_value(history,
                                               F_STONITH_DIFFERENTIAL))) {
                out_history =
                    stonith_local_history_diff(received_history, TRUE, NULL);
                if (out_history) {
                    crm_trace("Broadcasting history-diff to peers");
                    crm_xml_add(out_history, F_STONITH_DIFFERENTIAL,
                                XML_BOOLEAN_TRUE);
                    stonith_send_broadcast_history(out_history,
                        st_opt_broadcast | st_opt_discard_reply,
                        NULL);
                } else {
                    crm_trace("History-diff is empty - skip broadcast");
                }
            }
            stonith_merge_in_history_list(received_history);
        } else {
            crm_trace("Skipping history-query-broadcast (%s%s)"
                      " we sent ourselves",
                      remote_peer?"remote-peer=":"local-ipc",
                      remote_peer?remote_peer:"");
        }
    } else {
        /* plain history request */
        crm_trace("Looking for operations on %s in %p", target,
                  stonith_remote_op_list);
        *output = stonith_local_history_diff(NULL, FALSE, target);
    }
    free_xml(out_history);
    return rc;
}
int
cli_resource_clear_all_expired(xmlNode *root, cib_t *cib_conn, const char *rsc, const char *node, bool scope_master)
{
    xmlXPathObject *xpathObj = NULL;
    xmlNode *cib_constraints = NULL;
    crm_time_t *now = crm_time_new(NULL);
    int i;
    int rc = pcmk_ok;

    cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, root);
    xpathObj = xpath_search(cib_constraints, "//" XML_CONS_TAG_RSC_LOCATION);

    for (i = 0; i < numXpathResults(xpathObj); i++) {
        xmlNode *constraint_node = getXpathResult(xpathObj, i);
        xmlNode *date_expr_node = NULL;
        crm_time_t *end = NULL;
        char *xpath_string = NULL;

        xpath_string = build_clear_xpath_string(constraint_node, rsc, node, scope_master);
        if (xpath_string == NULL) {
            continue;
        }

        date_expr_node = get_xpath_object(xpath_string, constraint_node, LOG_DEBUG);
        if (date_expr_node == NULL) {
            free(xpath_string);
            continue;
        }

        /* And then finally, see if the date expression is expired.  If so,
         * clear the constraint.
         */
        end = crm_time_new(crm_element_value(date_expr_node, "end"));

        if (crm_time_compare(now, end) == 1) {
            xmlNode *fragment = NULL;
            xmlNode *location = NULL;

            fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
            location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
            crm_xml_set_id(location, "%s", ID(constraint_node));
            crm_log_xml_info(fragment, "Delete");

            rc = cib_conn->cmds->remove(cib_conn, XML_CIB_TAG_CONSTRAINTS,
                                        fragment, cib_options);
            if (rc != pcmk_ok) {
                free(xpath_string);
                goto bail;
            }

            free_xml(fragment);
        }

        crm_time_free(end);
        free(xpath_string);
    }

    rc = pcmk_ok;

bail:
    freeXpathObject(xpathObj);
    crm_time_free(now);
    return rc;
}
Example #21
0
enum crmd_fsa_input
handle_request(xmlNode * stored_msg)
{
    xmlNode *msg = NULL;
    const char *op = crm_element_value(stored_msg, F_CRM_TASK);

    /* Optimize this for the DC - it has the most to do */

    if (op == NULL) {
        crm_log_xml_err(stored_msg, "Bad message");
        return I_NULL;
    }

    /*========== DC-Only Actions ==========*/
    if (AM_I_DC) {
        if (strcmp(op, CRM_OP_JOIN_ANNOUNCE) == 0) {
            return I_NODE_JOIN;

        } else if (strcmp(op, CRM_OP_JOIN_REQUEST) == 0) {
            return I_JOIN_REQUEST;

        } else if (strcmp(op, CRM_OP_JOIN_CONFIRM) == 0) {
            return I_JOIN_RESULT;

        } else if (strcmp(op, CRM_OP_SHUTDOWN) == 0) {
            const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
            gboolean dc_match = safe_str_eq(host_from, fsa_our_dc);

            if (is_set(fsa_input_register, R_SHUTDOWN)) {
                crm_info("Shutting ourselves down (DC)");
                return I_STOP;

            } else if (dc_match) {
                crm_err("We didnt ask to be shut down, yet our"
                        " TE is telling us too." " Better get out now!");
                return I_TERMINATE;

            } else if (fsa_state != S_STOPPING) {
                crm_err("Another node is asking us to shutdown" " but we think we're ok.");
                return I_ELECTION;
            }

        } else if (strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) {
            /* a slave wants to shut down */
            /* create cib fragment and add to message */
            return handle_shutdown_request(stored_msg);
        }
    }

    /*========== common actions ==========*/
    if (strcmp(op, CRM_OP_NOVOTE) == 0) {
        ha_msg_input_t fsa_input;

        fsa_input.msg = stored_msg;
        register_fsa_input_adv(C_HA_MESSAGE, I_NULL, &fsa_input,
                               A_ELECTION_COUNT | A_ELECTION_CHECK, FALSE, __FUNCTION__);

    } else if (strcmp(op, CRM_OP_CLEAR_FAILCOUNT) == 0) {
        return handle_failcount_op(stored_msg);

    } else if (strcmp(op, CRM_OP_VOTE) == 0) {
        /* count the vote and decide what to do after that */
        ha_msg_input_t fsa_input;

        fsa_input.msg = stored_msg;
        register_fsa_input_adv(C_HA_MESSAGE, I_NULL, &fsa_input,
                               A_ELECTION_COUNT | A_ELECTION_CHECK, FALSE, __FUNCTION__);

        /* Sometimes we _must_ go into S_ELECTION */
        if (fsa_state == S_HALT) {
            crm_debug("Forcing an election from S_HALT");
            return I_ELECTION;
#if 0
        } else if (AM_I_DC) {
            /* This is the old way of doing things but what is gained? */
            return I_ELECTION;
#endif
        }

    } else if (strcmp(op, CRM_OP_JOIN_OFFER) == 0) {
        crm_debug("Raising I_JOIN_OFFER: join-%s", crm_element_value(stored_msg, F_CRM_JOIN_ID));
        return I_JOIN_OFFER;

    } else if (strcmp(op, CRM_OP_JOIN_ACKNAK) == 0) {
        crm_debug("Raising I_JOIN_RESULT: join-%s", crm_element_value(stored_msg, F_CRM_JOIN_ID));
        return I_JOIN_RESULT;

    } else if (strcmp(op, CRM_OP_LRM_DELETE) == 0
               || strcmp(op, CRM_OP_LRM_FAIL) == 0
               || strcmp(op, CRM_OP_LRM_REFRESH) == 0 || strcmp(op, CRM_OP_REPROBE) == 0) {

        crm_xml_add(stored_msg, F_CRM_SYS_TO, CRM_SYSTEM_LRMD);
        return I_ROUTER;

    } else if (strcmp(op, CRM_OP_NOOP) == 0) {
        return I_NULL;

    } else if (strcmp(op, CRM_OP_LOCAL_SHUTDOWN) == 0) {

        crm_shutdown(SIGTERM);
        /*return I_SHUTDOWN; */
        return I_NULL;

        /*========== (NOT_DC)-Only Actions ==========*/
    } else if (AM_I_DC == FALSE && strcmp(op, CRM_OP_SHUTDOWN) == 0) {

        const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
        gboolean dc_match = safe_str_eq(host_from, fsa_our_dc);

        if (dc_match || fsa_our_dc == NULL) {
            if (is_set(fsa_input_register, R_SHUTDOWN) == FALSE) {
                crm_err("We didn't ask to be shut down, yet our" " DC is telling us too.");
                set_bit(fsa_input_register, R_STAYDOWN);
                return I_STOP;
            }
            crm_info("Shutting down");
            return I_STOP;

        } else {
            crm_warn("Discarding %s op from %s", op, host_from);
        }

    } else if (strcmp(op, CRM_OP_PING) == 0) {
        /* eventually do some stuff to figure out
         * if we /are/ ok
         */
        const char *sys_to = crm_element_value(stored_msg, F_CRM_SYS_TO);
        xmlNode *ping = create_xml_node(NULL, XML_CRM_TAG_PING);

        crm_xml_add(ping, XML_PING_ATTR_STATUS, "ok");
        crm_xml_add(ping, XML_PING_ATTR_SYSFROM, sys_to);
        crm_xml_add(ping, "crmd_state", fsa_state2string(fsa_state));

        /* Ok, so technically not so interesting, but CTS needs to see this */
        crm_notice("Current ping state: %s", fsa_state2string(fsa_state));

        msg = create_reply(stored_msg, ping);
        relay_message(msg, TRUE);

        free_xml(ping);
        free_xml(msg);

    } else if (strcmp(op, CRM_OP_RM_NODE_CACHE) == 0) {
        int id = 0;
        const char *name = NULL;
        xmlNode *options = get_xpath_object("//" XML_TAG_OPTIONS, stored_msg, LOG_ERR);

        if (options) {
            crm_element_value_int(options, XML_ATTR_ID, &id);
            name = crm_element_value(options, XML_ATTR_UNAME);
        }

        reap_crm_member(id, name);

    } else {
        crm_err("Unexpected request (%s) sent to %s", op, AM_I_DC ? "the DC" : "non-DC node");
        crm_log_xml_err(stored_msg, "Unexpected");
    }

    return I_NULL;
}
Example #22
0
/*
 * Unpack everything
 * At the end you'll have:
 *  - A list of nodes
 *  - A list of resources (each with any dependencies on other resources)
 *  - A list of constraints between resources and nodes
 *  - A list of constraints between start/stop actions
 *  - A list of nodes that need to be stonith'd
 *  - A list of nodes that need to be shutdown
 *  - A list of the possible stop/start actions (without dependencies)
 */
gboolean
cluster_status(pe_working_set_t * data_set)
{
    xmlNode *config = get_xpath_object("//"XML_CIB_TAG_CRMCONFIG, data_set->input, LOG_TRACE);
    xmlNode *cib_nodes = get_xpath_object("//"XML_CIB_TAG_NODES, data_set->input, LOG_TRACE);
    xmlNode *cib_resources = get_xpath_object("//"XML_CIB_TAG_RESOURCES, data_set->input, LOG_TRACE);
    xmlNode *cib_status = get_xpath_object("//"XML_CIB_TAG_STATUS, data_set->input, LOG_TRACE);
    xmlNode *cib_tags = get_xpath_object("//"XML_CIB_TAG_TAGS, data_set->input, LOG_TRACE);
    const char *value = crm_element_value(data_set->input, XML_ATTR_HAVE_QUORUM);

    crm_trace("Beginning unpack");
    pe_dataset = data_set;

    /* reset remaining global variables */
    data_set->failed = create_xml_node(NULL, "failed-ops");

    if (data_set->input == NULL) {
        return FALSE;
    }

    if (data_set->now == NULL) {
        data_set->now = crm_time_new(NULL);
    }

    if (data_set->dc_uuid == NULL
        && data_set->input != NULL
        && crm_element_value(data_set->input, XML_ATTR_DC_UUID) != NULL) {
        /* this should always be present */
        data_set->dc_uuid = crm_element_value_copy(data_set->input, XML_ATTR_DC_UUID);
    }

    clear_bit(data_set->flags, pe_flag_have_quorum);
    if (crm_is_true(value)) {
        set_bit(data_set->flags, pe_flag_have_quorum);
    }

    data_set->op_defaults = get_xpath_object("//"XML_CIB_TAG_OPCONFIG, data_set->input, LOG_TRACE);
    data_set->rsc_defaults = get_xpath_object("//"XML_CIB_TAG_RSCCONFIG, data_set->input, LOG_TRACE);

    unpack_config(config, data_set);

   if (is_not_set(data_set->flags, pe_flag_quick_location)
       && is_not_set(data_set->flags, pe_flag_have_quorum)
       && data_set->no_quorum_policy != no_quorum_ignore) {
        crm_warn("Fencing and resource management disabled due to lack of quorum");
    }

    unpack_nodes(cib_nodes, data_set);

    if(is_not_set(data_set->flags, pe_flag_quick_location)) {
        unpack_remote_nodes(cib_resources, data_set);
    }

    unpack_resources(cib_resources, data_set);
    unpack_tags(cib_tags, data_set);

    if(is_not_set(data_set->flags, pe_flag_quick_location)) {
        unpack_status(cib_status, data_set);
    }

    set_bit(data_set->flags, pe_flag_have_status);
    return TRUE;
}
Example #23
0
void
abort_transition_graph(int abort_priority, enum transition_action abort_action,
                       const char *abort_text, xmlNode * reason, const char *fn, int line)
{
    int log_level = LOG_INFO;
    const char *magic = NULL;

    CRM_CHECK(transition_graph != NULL, return);

    if (reason) {
        int diff_add_updates = 0;
        int diff_add_epoch = 0;
        int diff_add_admin_epoch = 0;

        int diff_del_updates = 0;
        int diff_del_epoch = 0;
        int diff_del_admin_epoch = 0;
        xmlNode *diff = get_xpath_object("//" F_CIB_UPDATE_RESULT "//diff", reason, LOG_DEBUG_2);

        magic = crm_element_value(reason, XML_ATTR_TRANSITION_MAGIC);

        if (diff) {
            cib_diff_version_details(diff,
                                     &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
                                     &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
            if (crm_str_eq(TYPE(reason), XML_CIB_TAG_NVPAIR, TRUE)) {
                do_crm_log(log_level,
                           "%s:%d - Triggered transition abort (complete=%d, tag=%s, id=%s, name=%s, value=%s, magic=%s, cib=%d.%d.%d) : %s",
                           fn, line, transition_graph->complete, TYPE(reason), ID(reason),
                           NAME(reason), VALUE(reason), magic ? magic : "NA", diff_add_admin_epoch,
                           diff_add_epoch, diff_add_updates, abort_text);
            } else {
                do_crm_log(log_level,
                           "%s:%d - Triggered transition abort (complete=%d, tag=%s, id=%s, magic=%s, cib=%d.%d.%d) : %s",
                           fn, line, transition_graph->complete, TYPE(reason), ID(reason),
                           magic ? magic : "NA", diff_add_admin_epoch, diff_add_epoch,
                           diff_add_updates, abort_text);
            }

        } else {
            do_crm_log(log_level,
                       "%s:%d - Triggered transition abort (complete=%d, tag=%s, id=%s, magic=%s) : %s",
                       fn, line, transition_graph->complete, TYPE(reason), ID(reason),
                       magic ? magic : "NA", abort_text);
        }

    } else {
        do_crm_log(log_level,
                   "%s:%d - Triggered transition abort (complete=%d) : %s",
                   fn, line, transition_graph->complete, abort_text);
    }

    switch (fsa_state) {
    case S_STARTING:
    case S_PENDING:
    case S_NOT_DC:
    case S_HALT:
    case S_ILLEGAL:
    case S_STOPPING:
    case S_TERMINATE:
        do_crm_log(log_level,
                   "Abort suppressed: state=%s (complete=%d)",
                   fsa_state2string(fsa_state), transition_graph->complete);
        return;
    default:
        break;
    }

    if (magic == NULL && reason != NULL) {
        crm_log_xml(log_level + 1, "Cause", reason);
    }

    /* Make sure any queued calculations are discarded ASAP */
    crm_free(fsa_pe_ref);
    fsa_pe_ref = NULL;

    if (transition_graph->complete) {
        if (transition_timer->period_ms > 0) {
            crm_timer_start(transition_timer);
        } else {
            register_fsa_input(C_FSA_INTERNAL, I_PE_CALC, NULL);
        }
        return;
    }

    update_abort_priority(transition_graph, abort_priority, abort_action, abort_text);

    mainloop_set_trigger(transition_trigger);
}