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
void
throttle_update(xmlNode *xml)
{
    int max = 0;
    enum throttle_state_e mode = 0;
    struct throttle_record_s *r = NULL;
    const char *from = crm_element_value(xml, F_CRM_HOST_FROM);

    crm_element_value_int(xml, F_CRM_THROTTLE_MODE, (int*)&mode);
    crm_element_value_int(xml, F_CRM_THROTTLE_MAX, &max);

    r = g_hash_table_lookup(throttle_records, from);

    if(r == NULL) {
        r = calloc(1, sizeof(struct throttle_record_s));
        r->node = strdup(from);
        g_hash_table_insert(throttle_records, r->node, r);
    }

    r->max = max;
    r->mode = mode;

    crm_debug("Host %s supports a maximum of %d jobs and throttle mode %.4x.  New job limit is %d",
              from, max, mode, throttle_get_job_limit(from));
}
Example #3
0
static void
mcp_cpg_deliver(cpg_handle_t handle,
                 const struct cpg_name *groupName,
                 uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
{
    xmlNode *xml = string2xml(msg);
    const char *task = crm_element_value(xml, F_CRM_TASK);

    crm_trace("Received %s %.200s", task, msg);
    if (task == NULL && nodeid != local_nodeid) {
        uint32_t procs = 0;
        const char *uname = crm_element_value(xml, "uname");

        crm_element_value_int(xml, "proclist", (int *)&procs);
        /* crm_debug("Got proclist %.32x from %s", procs, uname); */
        if (update_node_processes(nodeid, uname, procs)) {
            update_process_clients(NULL);
        }

    } else if (crm_str_eq(task, CRM_OP_RM_NODE_CACHE, TRUE)) {
        int id = 0;
        const char *name = NULL;

        crm_element_value_int(xml, XML_ATTR_ID, &id);
        name = crm_element_value(xml, XML_ATTR_UNAME);
        reap_crm_member(id, name);
    }
}
Example #4
0
static gboolean
is_matched_failure(const char *rsc_id, xmlNode *conf_op_xml,
                   xmlNode *lrm_op_xml)
{
    gboolean matched = FALSE;
    const char *conf_op_name = NULL;
    int conf_op_interval = 0;
    const char *lrm_op_task = NULL;
    int lrm_op_interval = 0;
    const char *lrm_op_id = NULL;
    char *last_failure_key = NULL;

    if (rsc_id == NULL || conf_op_xml == NULL || lrm_op_xml == NULL) {
        return FALSE;
    }

    conf_op_name = crm_element_value(conf_op_xml, "name");
    conf_op_interval = crm_get_msec(crm_element_value(conf_op_xml, "interval"));
    lrm_op_task = crm_element_value(lrm_op_xml, XML_LRM_ATTR_TASK);
    crm_element_value_int(lrm_op_xml, XML_LRM_ATTR_INTERVAL, &lrm_op_interval);

    if (safe_str_eq(conf_op_name, lrm_op_task) == FALSE
        || conf_op_interval != lrm_op_interval) {
        return FALSE;
    }

    lrm_op_id = ID(lrm_op_xml);
    last_failure_key = generate_op_key(rsc_id, "last_failure", 0);

    if (safe_str_eq(last_failure_key, lrm_op_id)) {
        matched = TRUE;

    } else {
        char *expected_op_key = generate_op_key(rsc_id, conf_op_name,
                                                conf_op_interval);

        if (safe_str_eq(expected_op_key, lrm_op_id)) {
            int rc = 0;
            int target_rc = get_target_rc(lrm_op_xml);

            crm_element_value_int(lrm_op_xml, XML_LRM_ATTR_RC, &rc);
            if (rc != target_rc) {
                matched = TRUE;
            }
        }
        free(expected_op_key);
    }

    free(last_failure_key);
    return matched;
}
void
te_update_diff(const char *event, xmlNode * msg)
{
    xmlNode *diff = NULL;
    const char *op = NULL;
    int rc = -EINVAL;
    int format = 1;
    int p_add[] = { 0, 0, 0 };
    int p_del[] = { 0, 0, 0 };

    CRM_CHECK(msg != NULL, return);
    crm_element_value_int(msg, F_CIB_RC, &rc);

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

    } else if (rc < pcmk_ok) {
        crm_trace("Filter rc=%d (%s)", rc, pcmk_strerror(rc));
        return;

    } else if (transition_graph->complete
               && fsa_state != S_IDLE
               && fsa_state != S_TRANSITION_ENGINE
               && fsa_state != S_POLICY_ENGINE) {
        crm_trace("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);

    xml_patch_versions(diff, p_add, p_del);
    crm_debug("Processing (%s) diff: %d.%d.%d -> %d.%d.%d (%s)", op,
              p_del[0], p_del[1], p_del[2], p_add[0], p_add[1], p_add[2],
              fsa_state2string(fsa_state));

    crm_element_value_int(diff, "format", &format);
    switch (format) {
        case 1:
            te_update_diff_v1(event, diff);
            break;
        case 2:
            te_update_diff_v2(diff);
            break;
        default:
            crm_warn("Ignoring malformed CIB update (unknown patch format %d)",
                     format);
    }
}
Example #6
0
void
cib_peer_callback(xmlNode * msg, void *private_data)
{
    const char *reason = NULL;
    const char *originator = crm_element_value(msg, F_ORIG);

    if (originator == NULL || crm_str_eq(originator, cib_our_uname, TRUE)) {
        /* message is from ourselves */
        int bcast_id = 0;
        if (!(crm_element_value_int(msg, F_CIB_LOCAL_NOTIFY_ID, &bcast_id))) {
            check_local_notify(bcast_id);
        }
        return;

    } else if (crm_peer_cache == NULL) {
        reason = "membership not established";
        goto bail;
    }

    if (crm_element_value(msg, F_CIB_CLIENTNAME) == NULL) {
        crm_xml_add(msg, F_CIB_CLIENTNAME, originator);
    }

    /* crm_log_xml_trace("Peer[inbound]", msg); */
    cib_process_request(msg, FALSE, TRUE, TRUE, NULL);
    return;

  bail:
    if (reason) {
        const char *seq = crm_element_value(msg, F_SEQ);
        const char *op = crm_element_value(msg, F_CIB_OPERATION);

        crm_warn("Discarding %s message (%s) from %s: %s", op, seq, originator, reason);
    }
}
Example #7
0
/*!
 * \internal
 * \brief Return host's hash table entry (creating one if needed)
 *
 * \param[in] values Hash table of values
 * \param[in] host Name of peer to look up
 * \param[in] xml XML describing the attribute
 *
 * \return Pointer to new or existing hash table entry
 */
static attribute_value_t *
attrd_lookup_or_create_value(GHashTable *values, const char *host, xmlNode *xml)
{
    attribute_value_t *v = g_hash_table_lookup(values, host);
    int is_remote = 0;

    crm_element_value_int(xml, F_ATTRD_IS_REMOTE, &is_remote);
    if (is_remote) {
        /* If we previously assumed this node was an unseen cluster node,
         * remove its entry from the cluster peer cache.
         */
        crm_node_t *dup = crm_find_peer(0, host);

        if (dup && (dup->uuid == NULL)) {
            reap_crm_member(0, host);
        }

        /* Ensure this host is in the remote peer cache */
        crm_remote_peer_cache_add(host);
    }

    if (v == NULL) {
        v = calloc(1, sizeof(attribute_value_t));
        CRM_ASSERT(v != NULL);

        v->nodename = strdup(host);
        CRM_ASSERT(v->nodename != NULL);

        v->is_remote = is_remote;
        g_hash_table_replace(values, v->nodename, v);
    }
    return(v);
}
Example #8
0
static attribute_t *
create_attribute(xmlNode *xml)
{
    int dampen = 0;
    const char *value = crm_element_value(xml, F_ATTRD_DAMPEN);
    attribute_t *a = calloc(1, sizeof(attribute_t));

    a->id      = crm_element_value_copy(xml, F_ATTRD_ATTRIBUTE);
    a->set     = crm_element_value_copy(xml, F_ATTRD_SET);
    a->uuid    = crm_element_value_copy(xml, F_ATTRD_KEY);
    a->values = g_hash_table_new_full(crm_strcase_hash, crm_strcase_equal, NULL, free_attribute_value);

    crm_element_value_int(xml, F_ATTRD_IS_PRIVATE, &a->is_private);

#if ENABLE_ACL
    crm_trace("Performing all %s operations as user '%s'", a->id, a->user);
    a->user = crm_element_value_copy(xml, F_ATTRD_USER);
#endif

    if(value) {
        dampen = crm_get_msec(value);
        crm_trace("Created attribute %s with delay %dms (%s)", a->id, dampen, value);
    } else {
        crm_trace("Created attribute %s with no delay", a->id);
    }

    if(dampen > 0) {
        a->timeout_ms = dampen;
        a->timer = mainloop_timer_add(a->id, a->timeout_ms, FALSE, attribute_timer_cb, a);
    }

    g_hash_table_replace(attributes, a->id, a);
    return a;
}
Example #9
0
void
cib_common_callback_worker(uint32_t id, uint32_t flags, xmlNode * op_request,
                           crm_client_t * cib_client, gboolean privileged)
{
    const char *op = crm_element_value(op_request, F_CIB_OPERATION);

    if (crm_str_eq(op, CRM_OP_REGISTER, TRUE)) {
        if (flags & crm_ipc_client_response) {
            xmlNode *ack = create_xml_node(NULL, __FUNCTION__);

            crm_xml_add(ack, F_CIB_OPERATION, CRM_OP_REGISTER);
            crm_xml_add(ack, F_CIB_CLIENTID, cib_client->id);
            crm_ipcs_send(cib_client, id, ack, flags);
            cib_client->request_id = 0;
            free_xml(ack);
        }
        return;

    } else if (crm_str_eq(op, T_CIB_NOTIFY, TRUE)) {
        /* Update the notify filters for this client */
        int on_off = 0;
        long long bit = 0;
        const char *type = crm_element_value(op_request, F_CIB_NOTIFY_TYPE);

        crm_element_value_int(op_request, F_CIB_NOTIFY_ACTIVATE, &on_off);

        crm_debug("Setting %s callbacks for %s (%s): %s",
                  type, cib_client->name, cib_client->id, on_off ? "on" : "off");

        if (safe_str_eq(type, T_CIB_POST_NOTIFY)) {
            bit = cib_notify_post;

        } else if (safe_str_eq(type, T_CIB_PRE_NOTIFY)) {
            bit = cib_notify_pre;

        } else if (safe_str_eq(type, T_CIB_UPDATE_CONFIRM)) {
            bit = cib_notify_confirm;

        } else if (safe_str_eq(type, T_CIB_DIFF_NOTIFY)) {
            bit = cib_notify_diff;

        } else if (safe_str_eq(type, T_CIB_REPLACE_NOTIFY)) {
            bit = cib_notify_replace;
        }

        if (on_off) {
            set_bit(cib_client->options, bit);
        } else {
            clear_bit(cib_client->options, bit);
        }

        if (flags & crm_ipc_client_response) {
            /* TODO - include rc */
            crm_ipcs_send_ack(cib_client, id, flags, "ack", __FUNCTION__, __LINE__);
        }
        return;
    }

    cib_process_request(op_request, FALSE, privileged, FALSE, cib_client);
}
Example #10
0
static void
remote_proxy_cb(lrmd_t *lrmd, void *userdata, xmlNode *msg)
{
    lrm_state_t *lrm_state = userdata;
    const char *op = crm_element_value(msg, F_LRMD_IPC_OP);
    const char *session = crm_element_value(msg, F_LRMD_IPC_SESSION);
    int msg_id = 0;

    /* sessions are raw ipc connections to IPC,
     * all we do is proxy requests/responses exactly
     * like they are given to us at the ipc level. */

    CRM_CHECK(op != NULL, return);
    CRM_CHECK(session != NULL, return);

    crm_element_value_int(msg, F_LRMD_IPC_MSG_ID, &msg_id);

    /* This is msg from remote ipc client going to real ipc server */
    if (safe_str_eq(op, "new")) {
        const char *channel = crm_element_value(msg, F_LRMD_IPC_IPC_SERVER);

        CRM_CHECK(channel != NULL, return);

        if (remote_proxy_new(lrm_state->node_name, session, channel) == NULL) {
            remote_proxy_notify_destroy(lrmd, session);
        }
        crm_info("new remote proxy client established to %s, session id %s", channel, session);
    } else if (safe_str_eq(op, "destroy")) {
Example #11
0
static int
lrmd_remote_client_msg(gpointer data)
{
    int id = 0;
    int rc = 0;
    int disconnected = 0;
    xmlNode *request = NULL;
    crm_client_t *client = data;

    if (client->remote->tls_handshake_complete == FALSE) {
        return remoted__read_handshake_data(client);
    }

    rc = crm_remote_ready(client->remote, 0);
    if (rc == 0) {
        /* no msg to read */
        return 0;
    } else if (rc < 0) {
        crm_info("Remote client disconnected while polling it");
        return -1;
    }

    crm_remote_recv(client->remote, -1, &disconnected);

    request = crm_remote_parse_buffer(client->remote);
    while (request) {
        crm_element_value_int(request, F_LRMD_REMOTE_MSG_ID, &id);
        crm_trace("Processing remote client request %d", id);
        if (!client->name) {
            const char *value = crm_element_value(request, F_LRMD_CLIENTNAME);

            if (value) {
                client->name = strdup(value);
            }
        }

        lrmd_call_id++;
        if (lrmd_call_id < 1) {
            lrmd_call_id = 1;
        }

        crm_xml_add(request, F_LRMD_CLIENTID, client->id);
        crm_xml_add(request, F_LRMD_CLIENTNAME, client->name);
        crm_xml_add_int(request, F_LRMD_CALLID, lrmd_call_id);

        process_lrmd_message(client, id, request);
        free_xml(request);

        /* process all the messages in the current buffer */
        request = crm_remote_parse_buffer(client->remote);
    }

    if (disconnected) {
        crm_info("Remote client disconnected while reading from it");
        return -1;
    }

    return 0;
}
Example #12
0
void
cibmon_diff(const char *event, xmlNode * msg)
{
    int rc = -1;
    const char *op = NULL;
    unsigned int log_level = LOG_INFO;

    xmlNode *diff = NULL;
    xmlNode *cib_last = NULL;
    xmlNode *update = get_message_xml(msg, F_CIB_UPDATE);

    if (msg == NULL) {
        crm_err("NULL update");
        return;
    }

    crm_element_value_int(msg, F_CIB_RC, &rc);
    op = crm_element_value(msg, F_CIB_OPERATION);
    diff = get_message_xml(msg, F_CIB_UPDATE_RESULT);

    if (rc < pcmk_ok) {
        log_level = LOG_WARNING;
        do_crm_log(log_level, "[%s] %s ABORTED: %s", event, op, pcmk_strerror(rc));
        return;
    }

    if (log_diffs) {
        xml_log_patchset(log_level, op, diff);
    }

    if (log_updates && update != NULL) {
        crm_log_xml_trace(update, "raw_update");
    }

    if (cib_copy != NULL) {
        cib_last = cib_copy;
        cib_copy = NULL;
        rc = cib_process_diff(op, cib_force_diff, NULL, NULL, diff, cib_last, &cib_copy, NULL);

        if (rc != pcmk_ok) {
            crm_debug("Update didn't apply, requesting full copy: %s", pcmk_strerror(rc));
            free_xml(cib_copy);
            cib_copy = NULL;
        }
    }

    if (cib_copy == NULL) {
        rc = cib->cmds->query(cib, NULL, &cib_copy, cib_scope_local | cib_sync_call);
    }

    if(rc == -EACCES) {
        crm_exit(CRM_EX_INSUFFICIENT_PRIV);
    }

    free_xml(cib_last);
}
Example #13
0
void
ipc_proxy_forward_client(crm_client_t *ipc_proxy, xmlNode *xml)
{
    const char *session = crm_element_value(xml, F_LRMD_IPC_SESSION);
    const char *msg_type = crm_element_value(xml, F_LRMD_IPC_OP);
    xmlNode *msg = get_message_xml(xml, F_LRMD_IPC_MSG);
    crm_client_t *ipc_client = crm_client_get_by_id(session);
    int rc = 0;

    if (ipc_client == NULL) {
        xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
        crm_xml_add(msg, F_LRMD_IPC_OP, "destroy");
        crm_xml_add(msg, F_LRMD_IPC_SESSION, session);
        lrmd_server_send_notify(ipc_proxy, msg);
        free_xml(msg);
        return;
    }

    /* This is an event or response from the ipc provider
     * going to the local ipc client.
     *
     * Looking at the chain of events.
     *
     * -----remote node----------------|---- cluster node ------
     * ipc_client <--1--> this code <--2--> crmd:remote_proxy_cb/remote_proxy_relay_event() <----3----> ipc server
     *
     * This function is receiving a msg from connection 2
     * and forwarding it to connection 1.
     */

    if (safe_str_eq(msg_type, "event")) {
        crm_info("Sending event to %s", ipc_client->id);
        rc = crm_ipcs_send(ipc_client, 0, msg, crm_ipc_server_event);

    } else if (safe_str_eq(msg_type, "response")) {
        int msg_id = 0;

        crm_element_value_int(xml, F_LRMD_IPC_MSG_ID, &msg_id);
        crm_info("Sending response to %d - %s", ipc_client->request_id, ipc_client->id);
        rc = crm_ipcs_send(ipc_client, msg_id, msg, FALSE);

        CRM_LOG_ASSERT(msg_id == ipc_client->request_id);
        ipc_client->request_id = 0;

    } else if (safe_str_eq(msg_type, "destroy")) {
        qb_ipcs_disconnect(ipc_client->ipcs);

    } else {
        crm_err("Unknown ipc proxy msg type %s" , msg_type);
    }

    if (rc < 0) {
        crm_warn("IPC Proxy send to ipc client %s failed, rc = %d", ipc_client->id, rc);
    }
}
Example #14
0
/*!
 * \internal
 * \brief Convert xml fence-history to a hash-table like stonith_remote_op_list
 *
 * \param[in] history   Fence-history in xml
 *
 * \return Fence-history as hash-table
 */
static GHashTable *
stonith_xml_history_to_list(xmlNode *history)
{
    xmlNode *xml_op = NULL;
    GHashTable *rv = NULL;

    init_stonith_remote_op_hash_table(&rv);

    CRM_LOG_ASSERT(rv != NULL);

    for (xml_op = __xml_first_child(history); xml_op != NULL;
         xml_op = __xml_next(xml_op)) {
        remote_fencing_op_t *op = NULL;
        char *id = crm_element_value_copy(xml_op, F_STONITH_REMOTE_OP_ID);
        int completed, state;

        if (!id) {
            crm_warn("History to convert to hashtable has no id in entry");
            continue;
        }

        crm_trace("Attaching op %s to hashtable", id);

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

        op->id = id;
        op->target = crm_element_value_copy(xml_op, F_STONITH_TARGET);
        op->action = crm_element_value_copy(xml_op, F_STONITH_ACTION);
        op->originator = crm_element_value_copy(xml_op, F_STONITH_ORIGIN);
        op->delegate = crm_element_value_copy(xml_op, F_STONITH_DELEGATE);
        op->client_name = crm_element_value_copy(xml_op, F_STONITH_CLIENTNAME);
        crm_element_value_int(xml_op, F_STONITH_DATE, &completed);
        op->completed = (time_t) completed;
        crm_element_value_int(xml_op, F_STONITH_STATE, &state);
        op->state = (enum op_state) state;

        g_hash_table_replace(rv, id, op);
        CRM_LOG_ASSERT(g_hash_table_lookup(rv, id) != NULL);
    }

    return rv;
}
Example #15
0
int32_t
cib_common_callback(qb_ipcs_connection_t * c, void *data, size_t size, gboolean privileged)
{
    uint32_t id = 0;
    uint32_t flags = 0;
    int call_options = 0;
    crm_client_t *cib_client = crm_client_get(c);
    xmlNode *op_request = crm_ipcs_recv(cib_client, data, size, &id, &flags);

    if (op_request) {
        crm_element_value_int(op_request, F_CIB_CALLOPTS, &call_options);
    }

    if (op_request == NULL) {
        crm_trace("Invalid message from %p", c);
        crm_ipcs_send_ack(cib_client, id, flags, "nack", __FUNCTION__, __LINE__);
        return 0;

    } else if(cib_client == NULL) {
        crm_trace("Invalid client %p", c);
        return 0;
    }

    if (is_set(call_options, cib_sync_call)) {
        CRM_ASSERT(flags & crm_ipc_client_response);
        CRM_LOG_ASSERT(cib_client->request_id == 0);    /* This means the client has two synchronous events in-flight */
        cib_client->request_id = id;    /* Reply only to the last one */
    }

    if (cib_client->name == NULL) {
        const char *value = crm_element_value(op_request, F_CIB_CLIENTNAME);

        if (value == NULL) {
            cib_client->name = crm_itoa(cib_client->pid);
        } else {
            cib_client->name = strdup(value);
        }
    }

    crm_xml_add(op_request, F_CIB_CLIENTID, cib_client->id);
    crm_xml_add(op_request, F_CIB_CLIENTNAME, cib_client->name);

#if ENABLE_ACL
    CRM_ASSERT(cib_client->user != NULL);
    crm_acl_get_set_user(op_request, F_CIB_USER, cib_client->user);
#endif

    crm_log_xml_trace(op_request, "Client[inbound]");

    cib_common_callback_worker(id, flags, op_request, cib_client, privileged);
    free_xml(op_request);

    return 0;
}
Example #16
0
void
cibmon_diff(const char *event, xmlNode * msg)
{
    int rc = -1;
    const char *op = NULL;
    unsigned int log_level = LOG_INFO;

    xmlNode *diff = NULL;
    xmlNode *cib_last = NULL;
    xmlNode *update = get_message_xml(msg, F_CIB_UPDATE);

    if (msg == NULL) {
        crm_err("NULL update");
        return;
    }

    crm_element_value_int(msg, F_CIB_RC, &rc);
    op = crm_element_value(msg, F_CIB_OPERATION);
    diff = get_message_xml(msg, F_CIB_UPDATE_RESULT);

    if (rc < cib_ok) {
        log_level = LOG_WARNING;
        do_crm_log(log_level, "[%s] %s ABORTED: %s", event, op, cib_error2string(rc));
        return;
    }

    if (log_diffs) {
        log_cib_diff(log_level, diff, op);
    }

    if (log_updates && update != NULL) {
        do_crm_log_xml(log_level + 2, "raw_update", update);
    }

    if (cib_copy != NULL) {
        cib_last = cib_copy;
        cib_copy = NULL;
        rc = cib_process_diff(op, cib_force_diff, NULL, NULL, diff, cib_last, &cib_copy, NULL);

        if (rc != cib_ok) {
            crm_debug("Update didn't apply, requesting full copy: %s", cib_error2string(rc));
            free_xml(cib_copy);
            cib_copy = NULL;
        }
    }

    if (cib_copy == NULL) {
        cib_copy = get_cib_copy(cib);
    }

    free_xml(cib_last);
}
Example #17
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 #18
0
/*!
 * \internal
 * \brief Process a CPG message (process list or manual peer cache removal)
 *
 * \param[in] handle     CPG connection (ignored)
 * \param[in] groupName  CPG group name (ignored)
 * \param[in] nodeid     ID of affected node
 * \param[in] pid        Process ID (ignored)
 * \param[in] msg        CPG XML message
 * \param[in] msg_len    Length of msg in bytes (ignored)
 */
static void
mcp_cpg_deliver(cpg_handle_t handle,
                 const struct cpg_name *groupName,
                 uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
{
    xmlNode *xml = string2xml(msg);
    const char *task = crm_element_value(xml, F_CRM_TASK);

    crm_trace("Received CPG message (%s): %.200s",
              (task? task : "process list"), msg);

    if (task == NULL) {
        if (nodeid == local_nodeid) {
            crm_info("Ignoring process list sent by peer for local node");
        } else {
            uint32_t procs = 0;
            const char *uname = crm_element_value(xml, "uname");

            crm_element_value_int(xml, "proclist", (int *)&procs);
            if (update_node_processes(nodeid, uname, procs)) {
                update_process_clients(NULL);
            }
        }

    } else if (crm_str_eq(task, CRM_OP_RM_NODE_CACHE, TRUE)) {
        int id = 0;
        const char *name = NULL;

        crm_element_value_int(xml, XML_ATTR_ID, &id);
        name = crm_element_value(xml, XML_ATTR_UNAME);
        reap_crm_member(id, name);
    }

    if (xml != NULL) {
        free_xml(xml);
    }
}
Example #19
0
/*	A_DC_JOIN_PROCESS_ACK	*/
void
do_dc_join_ack(long long action,
               enum crmd_fsa_cause cause,
               enum crmd_fsa_state cur_state,
               enum crmd_fsa_input current_input, fsa_data_t * msg_data)
{
    int join_id = -1;
    int call_id = 0;
    ha_msg_input_t *join_ack = fsa_typed_data(fsa_dt_ha_msg);

    const char *op = crm_element_value(join_ack->msg, F_CRM_TASK);
    const char *join_from = crm_element_value(join_ack->msg, F_CRM_HOST_FROM);
    crm_node_t *peer = crm_get_peer(0, join_from);

    if (safe_str_neq(op, CRM_OP_JOIN_CONFIRM) || peer == NULL) {
        crm_debug("Ignoring op=%s message from %s", op, join_from);
        return;
    }

    crm_trace("Processing ack from %s", join_from);
    crm_element_value_int(join_ack->msg, F_CRM_JOIN_ID, &join_id);

    if (peer->join != crm_join_finalized) {
        crm_info("Join not in progress: ignoring join-%d from %s (phase = %d)",
                 join_id, join_from, peer->join);
        return;

    } else if (join_id != current_join_id) {
        crm_err("Invalid response from %s: join-%d vs. join-%d",
                join_from, join_id, current_join_id);
        crm_update_peer_join(__FUNCTION__, peer, crm_join_nack);
        return;
    }

    crm_update_peer_join(__FUNCTION__, peer, crm_join_confirmed);

    crm_info("join-%d: Updating node state to %s for %s",
             join_id, CRMD_JOINSTATE_MEMBER, join_from);

    /* update CIB with the current LRM status from the node
     * We dont need to notify the TE of these updates, a transition will
     *   be started in due time
     */
    erase_status_tag(join_from, XML_CIB_TAG_LRM, cib_scope_local);
    fsa_cib_update(XML_CIB_TAG_STATUS, join_ack->xml,
                   cib_scope_local | cib_quorum_override | cib_can_create, call_id, NULL);
    fsa_register_cib_callback(call_id, FALSE, NULL, join_update_complete_callback);
    crm_debug("join-%d: Registered callback for LRM update %d", join_id, call_id);
}
Example #20
0
void
cib_common_callback_worker(xmlNode * op_request, cib_client_t * cib_client, gboolean privileged)
{
    const char *op = crm_element_value(op_request, F_CIB_OPERATION);

    if (crm_str_eq(op, CRM_OP_REGISTER, TRUE)) {
        xmlNode *ack = create_xml_node(NULL, __FUNCTION__);

        crm_xml_add(ack, F_CIB_OPERATION, CRM_OP_REGISTER);
        crm_xml_add(ack, F_CIB_CLIENTID, cib_client->id);
	crm_ipcs_send(cib_client->ipc, ack, FALSE);
        free_xml(ack);
        return;

    } else if (crm_str_eq(op, T_CIB_NOTIFY, TRUE)) {
        /* Update the notify filters for this client */
        int on_off = 0;
        int rc = pcmk_ok;
        const char *type = crm_element_value(op_request, F_CIB_NOTIFY_TYPE);
        crm_element_value_int(op_request, F_CIB_NOTIFY_ACTIVATE, &on_off);

        crm_debug("Setting %s callbacks for %s (%s): %s",
                  type, cib_client->name, cib_client->id, on_off ? "on" : "off");

        if (safe_str_eq(type, T_CIB_POST_NOTIFY)) {
            cib_client->post_notify = on_off;

        } else if (safe_str_eq(type, T_CIB_PRE_NOTIFY)) {
            cib_client->pre_notify = on_off;

        } else if (safe_str_eq(type, T_CIB_UPDATE_CONFIRM)) {
            cib_client->confirmations = on_off;

        } else if (safe_str_eq(type, T_CIB_DIFF_NOTIFY)) {
            cib_client->diffs = on_off;

        } else if (safe_str_eq(type, T_CIB_REPLACE_NOTIFY)) {
            cib_client->replace = on_off;
        } else {
            rc = -ENXIO;
        }
        /* Already ack'd */
        return;
    }

    cib_client->num_calls++;
    cib_process_request(op_request, FALSE, privileged, FALSE, cib_client);
}
Example #21
0
/* Exit code means? */
static int32_t
st_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size)
{
    uint32_t id = 0;
    uint32_t flags = 0;
    int call_options = 0;
    xmlNode *request = NULL;
    crm_client_t *c = crm_client_get(qbc);

    if (c == NULL) {
        crm_info("Invalid client: %p", qbc);
        return 0;
    }

    request = crm_ipcs_recv(c, data, size, &id, &flags);
    if (request == NULL) {
        crm_ipcs_send_ack(c, id, flags, "nack", __FUNCTION__, __LINE__);
        return 0;
    }

    if (c->name == NULL) {
        const char *value = crm_element_value(request, F_STONITH_CLIENTNAME);

        if (value == NULL) {
            value = "unknown";
        }
        c->name = g_strdup_printf("%s.%u", value, c->pid);
    }

    crm_element_value_int(request, F_STONITH_CALLOPTS, &call_options);
    crm_trace("Flags %u/%u for command %u from %s", flags, call_options, id, crm_client_name(c));

    if (is_set(call_options, st_opt_sync_call)) {
        CRM_ASSERT(flags & crm_ipc_client_response);
        CRM_LOG_ASSERT(c->request_id == 0);     /* This means the client has two synchronous events in-flight */
        c->request_id = id;     /* Reply only to the last one */
    }

    crm_xml_add(request, F_STONITH_CLIENTID, c->id);
    crm_xml_add(request, F_STONITH_CLIENTNAME, crm_client_name(c));
    crm_xml_add(request, F_STONITH_CLIENTNODE, stonith_our_uname);

    crm_log_xml_trace(request, "Client[inbound]");
    stonith_command(c, id, flags, request, NULL);

    free_xml(request);
    return 0;
}
Example #22
0
static void
remote_proxy_cb(lrmd_t *lrmd, void *userdata, xmlNode *msg)
{
    lrm_state_t *lrm_state = userdata;
    const char *op = crm_element_value(msg, F_LRMD_IPC_OP);
    const char *session = crm_element_value(msg, F_LRMD_IPC_SESSION);
    int msg_id = 0;

    /* sessions are raw ipc connections to IPC,
     * all we do is proxy requests/responses exactly
     * like they are given to us at the ipc level. */

    CRM_CHECK(op != NULL, return);
    CRM_CHECK(session != NULL, return);

    crm_element_value_int(msg, F_LRMD_IPC_MSG_ID, &msg_id);
    /* This is msg from remote ipc client going to real ipc server */

    if (safe_str_eq(op, LRMD_IPC_OP_SHUTDOWN_REQ)) {
        char *now_s = NULL;
        time_t now = time(NULL);

        crm_notice("Graceful proxy shutdown of %s", lrm_state->node_name);

        now_s = crm_itoa(now);
        update_attrd(lrm_state->node_name, XML_CIB_ATTR_SHUTDOWN, now_s, NULL, TRUE);
        free(now_s);

        remote_proxy_ack_shutdown(lrmd);
        return;

    } else if (safe_str_eq(op, LRMD_IPC_OP_NEW)) {
        int rc;
        const char *channel = crm_element_value(msg, F_LRMD_IPC_IPC_SERVER);

        CRM_CHECK(channel != NULL, return);

        if (remote_proxy_new(lrm_state->node_name, session, channel) == NULL) {
            remote_proxy_notify_destroy(lrmd, session);
        }
        crm_trace("new remote proxy client established to %s, session id %s", channel, session);

        /* Look up stonith-watchdog-timeout and send to the remote peer for validation */
        rc = fsa_cib_conn->cmds->query(fsa_cib_conn, XML_CIB_TAG_CRMCONFIG, NULL, cib_scope_local);
        fsa_cib_conn->cmds->register_callback_full(fsa_cib_conn, rc, 10, FALSE, lrmd, "remote_config_check", remote_config_check, NULL);
        
    } else if (safe_str_eq(op, LRMD_IPC_OP_DESTROY)) {
Example #23
0
static void
pcmk_cpg_deliver(cpg_handle_t handle,
                 const struct cpg_name *groupName,
                 uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
{
    if (nodeid != local_nodeid) {
        uint32_t procs = 0;
        xmlNode *xml = string2xml(msg);
        const char *uname = crm_element_value(xml, "uname");

        crm_element_value_int(xml, "proclist", (int *)&procs);
        /* crm_debug("Got proclist %.32x from %s", procs, uname); */
        if (update_node_processes(nodeid, uname, procs)) {
            update_process_clients();
        }
    }
}
Example #24
0
/* Exit code means? */
static int32_t
pcmk_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size)
{
    uint32_t id = 0;
    uint32_t flags = 0;
    const char *task = NULL;
    crm_client_t *c = crm_client_get(qbc);
    xmlNode *msg = crm_ipcs_recv(c, data, size, &id, &flags);

    crm_ipcs_send_ack(c, id, flags, "ack", __FUNCTION__, __LINE__);
    if (msg == NULL) {
        return 0;
    }

    task = crm_element_value(msg, F_CRM_TASK);
    if (crm_str_eq(task, CRM_OP_QUIT, TRUE)) {
        /* Time to quit */
        crm_notice("Shutting down in response to ticket %s (%s)",
                   crm_element_value(msg, F_CRM_REFERENCE), crm_element_value(msg, F_CRM_ORIGIN));
        pcmk_shutdown(15);

    } else if (crm_str_eq(task, CRM_OP_RM_NODE_CACHE, TRUE)) {
        /* Send to everyone */
        struct iovec *iov;
        int id = 0;
        const char *name = NULL;

        crm_element_value_int(msg, XML_ATTR_ID, &id);
        name = crm_element_value(msg, XML_ATTR_UNAME);
        crm_notice("Instructing peers to remove references to node %s/%u", name, id);

        iov = calloc(1, sizeof(struct iovec));
        iov->iov_base = dump_xml_unformatted(msg);
        iov->iov_len = 1 + strlen(iov->iov_base);
        send_cpg_iov(iov);

    } else {
        update_process_clients(c);
    }

    free_xml(msg);
    return 0;
}
Example #25
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 #26
0
static void
remote_proxy_cb(lrmd_t *lrmd, void *userdata, xmlNode *msg)
{
    lrm_state_t *lrm_state = userdata;
    const char *op = crm_element_value(msg, F_LRMD_IPC_OP);
    const char *session = crm_element_value(msg, F_LRMD_IPC_SESSION);
    int msg_id = 0;

    /* sessions are raw ipc connections to IPC,
     * all we do is proxy requests/responses exactly
     * like they are given to us at the ipc level. */

    CRM_CHECK(op != NULL, return);
    CRM_CHECK(session != NULL, return);

    crm_element_value_int(msg, F_LRMD_IPC_MSG_ID, &msg_id);
    /* This is msg from remote ipc client going to real ipc server */

    if (safe_str_eq(op, LRMD_IPC_OP_SHUTDOWN_REQ)) {
        char *now_s = NULL;
        time_t now = time(NULL);

        crm_notice("Graceful proxy shutdown of %s", lrm_state->node_name);

        now_s = crm_itoa(now);
        update_attrd(lrm_state->node_name, XML_CIB_ATTR_SHUTDOWN, now_s, NULL, TRUE);
        free(now_s);

        remote_proxy_ack_shutdown(lrmd);
        return;

    } else if (safe_str_eq(op, LRMD_IPC_OP_NEW)) {
        const char *channel = crm_element_value(msg, F_LRMD_IPC_IPC_SERVER);

        CRM_CHECK(channel != NULL, return);

        if (remote_proxy_new(lrm_state->node_name, session, channel) == NULL) {
            remote_proxy_notify_destroy(lrmd, session);
        }
        crm_trace("new remote proxy client established to %s, session id %s", channel, session);
    } else if (safe_str_eq(op, LRMD_IPC_OP_DESTROY)) {
Example #27
0
/*!
 * \internal
 * \brief Return host's hash table entry (creating one if needed)
 *
 * \param[in] values Hash table of values
 * \param[in] host Name of peer to look up
 * \param[in] xml XML describing the attribute
 *
 * \return Pointer to new or existing hash table entry
 */
static attribute_value_t *
attrd_lookup_or_create_value(GHashTable *values, const char *host, xmlNode *xml)
{
    attribute_value_t *v = g_hash_table_lookup(values, host);

    if (v == NULL) {
        v = calloc(1, sizeof(attribute_value_t));
        CRM_ASSERT(v != NULL);

        v->nodename = strdup(host);
        CRM_ASSERT(v->nodename != NULL);

        crm_element_value_int(xml, F_ATTRD_IS_REMOTE, &v->is_remote);
        if (v->is_remote == TRUE) {
            crm_remote_peer_cache_add(host);
        }

        g_hash_table_replace(values, v->nodename, v);
    }
    return(v);
}
Example #28
0
/*!
 * \internal
 * \brief Respond to a client peer-remove request (i.e. propagate to all peers)
 *
 * \param[in] client_name Name of client that made request (for log messages)
 * \param[in] xml         Root of request XML
 *
 * \return void
 */
void
attrd_client_peer_remove(const char *client_name, xmlNode *xml)
{
    // Host and ID are not used in combination, rather host has precedence
    const char *host = crm_element_value(xml, F_ATTRD_HOST);
    char *host_alloc = NULL;

    if (host == NULL) {
        int nodeid;

        crm_element_value_int(xml, F_ATTRD_HOST_ID, &nodeid);
        if (nodeid > 0) {
            crm_node_t *node = crm_find_peer(nodeid, NULL);
            char *host_alloc = NULL;

            if (node && node->uname) {
                // Use cached name if available
                host = node->uname;
            } else {
                // Otherwise ask cluster layer
                host_alloc = get_node_name(nodeid);
                host = host_alloc;
            }
            crm_xml_add(xml, F_ATTRD_HOST, host);
        }
    }

    if (host) {
        crm_info("Client %s is requesting all values for %s be removed",
                 client_name, host);
        send_attrd_message(NULL, xml); /* ends up at attrd_peer_message() */
        free(host_alloc);
    } else {
        crm_info("Ignoring request by client %s to remove all peer values without specifying peer",
                 client_name);
    }
}
Example #29
0
static void
get_date(pe_working_set_t * data_set)
{
    int value = 0;
    time_t original_date = 0;

    crm_element_value_int(data_set->input, "execution-date", &value);
    original_date = value;

    if (use_date) {
        data_set->now = crm_time_new(use_date);

    } else if(original_date) {
        char *when = NULL;

        data_set->now = crm_time_new(NULL);
        crm_time_set_timet(data_set->now, &original_date);

        when = crm_time_as_string(data_set->now, crm_time_log_date|crm_time_log_timeofday);
        printf("Using the original execution date of: %s\n", when);

        free(when);
    }
}
Example #30
0
void
te_update_diff(const char *event, xmlNode * msg)
{
    int rc = -1;
    const char *op = NULL;

    xmlNode *diff = 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_trace("No graph");
        return;

    } else if (rc < pcmk_ok) {
        crm_trace("Filter rc=%d (%s)", rc, pcmk_strerror(rc));
        return;

    } else if (transition_graph->complete == TRUE
               && fsa_state != S_IDLE
               && fsa_state != S_TRANSITION_ENGINE && fsa_state != S_POLICY_ENGINE) {
        crm_trace("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);

    if (cib_config_changed(NULL, NULL, &diff)) {
        abort_transition(INFINITY, tg_restart, "Non-status change", diff);
        goto bail;              /* configuration changed */
    }

    /* Tickets Attributes - Added/Updated */
    xpathObj =
        xpath_search(diff,
                     "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_CIB_TAG_TICKETS);
    if (xpathObj && xpathObj->nodesetval->nodeNr > 0) {
        xmlNode *aborted = getXpathResult(xpathObj, 0);

        abort_transition(INFINITY, tg_restart, "Ticket attribute: update", aborted);
        goto bail;

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

    /* Tickets Attributes - Removed */
    xpathObj =
        xpath_search(diff,
                     "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//" XML_CIB_TAG_TICKETS);
    if (xpathObj && xpathObj->nodesetval->nodeNr > 0) {
        xmlNode *aborted = getXpathResult(xpathObj, 0);

        abort_transition(INFINITY, tg_restart, "Ticket attribute: removal", aborted);
        goto bail;

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

    /* 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_trace(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 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_debug("Detected LRM refresh - %d resources updated: Skipping all resource events",
                      updates);
            crm_log_xml_trace(diff, "lrm-refresh");
            abort_transition(INFINITY, tg_restart, "LRM Refresh", NULL);
            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;
            rsc_op_xpath = calloc(1, 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);
                    }
                    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);
            }
            free(rsc_op_xpath);
        }
    }

  bail:
    if (xpathObj) {
        xmlXPathFreeObject(xpathObj);
    }
}