Exemplo n.º 1
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);
}
Exemplo n.º 2
0
static void
te_update_diff_v1(const char *event, xmlNode *diff)
{
    int lpc, max;
    xmlXPathObject *xpathObj = NULL;

    CRM_CHECK(diff != NULL, return);

    xml_log_patchset(LOG_TRACE, __FUNCTION__, diff);
    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 (numXpathResults(xpathObj) > 0) {
        xmlNode *aborted = getXpathResult(xpathObj, 0);

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

    }
    freeXpathObject(xpathObj);

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

        abort_transition(INFINITY, tg_restart, "Ticket attribute: removal", aborted);
        goto bail;
    }
    freeXpathObject(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);
    max = numXpathResults(xpathObj);

    for (lpc = 0; lpc < max; 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;
        }
    }

    freeXpathObject(xpathObj);

    /* Transient Attributes - Removed */
    xpathObj =
        xpath_search(diff,
                     "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//"
                     XML_TAG_TRANSIENT_NODEATTRS);
    if (numXpathResults(xpathObj) > 0) {
        xmlNode *aborted = getXpathResult(xpathObj, 0);

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

    }
    freeXpathObject(xpathObj);

    /*
     * Updates by, or in response to, TE actions will never contain updates
     * for more than one resource at a time, so such updates indicate an
     * LRM refresh.
     *
     * In that case, start a new transition rather than check each result
     * individually, which can result in _huge_ speedups in large clusters.
     *
     * Unfortunately, we can only do so when there are no pending actions.
     * Otherwise, we could mistakenly throw away those results here, and
     * the cluster will stall waiting for them and time out the operation.
     */
    if (transition_graph->pending == 0) {
        xpathObj = xpath_search(diff,
                                "//" F_CIB_UPDATE_RESULT
                                "//" XML_TAG_DIFF_ADDED
                                "//" XML_LRM_TAG_RESOURCE);
        max = numXpathResults(xpathObj);
        if (max > 1) {
            crm_debug("Ignoring resource operation updates due to history refresh of %d resources",
                      max);
            crm_log_xml_trace(diff, "lrm-refresh");
            abort_transition(INFINITY, tg_restart, "History refresh", NULL);
            goto bail;
        }
        freeXpathObject(xpathObj);
    }

    /* Process operation updates */
    xpathObj =
        xpath_search(diff,
                     "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_LRM_TAG_RSC_OP);
    max = numXpathResults(xpathObj);
    if (max > 0) {
        int lpc = 0;

        for (lpc = 0; lpc < max; lpc++) {
            xmlNode *rsc_op = getXpathResult(xpathObj, lpc);
            const char *node = get_node_id(rsc_op);

            process_graph_event(rsc_op, node);
        }
    }
    freeXpathObject(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);
    max = numXpathResults(xpathObj);
    for (lpc = 0; lpc < max; lpc++) {
        int path_max = 0;
        const char *op_id = NULL;
        char *rsc_op_xpath = NULL;
        xmlXPathObject *op_match = NULL;
        xmlNode *match = getXpathResult(xpathObj, lpc);

        CRM_LOG_ASSERT(match != NULL);
        if(match == NULL) { continue; };

        op_id = ID(match);

        path_max = strlen(RSC_OP_TEMPLATE) + strlen(op_id) + 1;
        rsc_op_xpath = calloc(1, path_max);
        snprintf(rsc_op_xpath, path_max, RSC_OP_TEMPLATE, op_id);

        op_match = xpath_search(diff, rsc_op_xpath);
        if (numXpathResults(op_match) == 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);
                freeXpathObject(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);
            }
        }

        freeXpathObject(op_match);
        free(rsc_op_xpath);
    }

  bail:
    freeXpathObject(xpathObj);
}
Exemplo n.º 3
0
int
main(int argc, char **argv)
{
    int rc = 0;
    int flag;
    int argerr = 0;
    static int command = '?';
    const char *validation = NULL;
    char *shadow = NULL;
    char *shadow_file = NULL;
    gboolean full_upload = FALSE;
    gboolean dangerous_cmd = FALSE;
    struct stat buf;
    int option_index = 0;

    crm_log_cli_init("crm_shadow");
    crm_set_options(NULL, "(query|command) [modifiers]", long_options,
                    "Perform configuration changes in a sandbox before updating the live cluster."
                    "\n\nSets up an environment in which configuration tools (cibadmin, crm_resource, etc) work"
                    " offline instead of against a live cluster, allowing changes to be previewed and tested"
                    " for side-effects.\n");

    if (argc < 2) {
        crm_help('?', EX_USAGE);
    }

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

        switch (flag) {
            case 'a':
                full_upload = TRUE;
                break;
            case 'd':
            case 'E':
            case 'p':
            case 'w':
            case 'F':
                command = flag;
                free(shadow);
                shadow = NULL;
                {
                    const char *env = getenv("CIB_shadow");
                    if(env) {
                        shadow = strdup(env);
                    } else {
                        fprintf(stderr, "No active shadow configuration defined\n");
                        crm_exit(ENOENT);
                    }
                }
                break;
            case 'v':
                validation = optarg;
                break;
            case 'e':
            case 'c':
            case 's':
            case 'r':
                command = flag;
                free(shadow);
                shadow = strdup(optarg);
                break;
            case 'C':
            case 'D':
                command = flag;
                dangerous_cmd = TRUE;
                free(shadow);
                shadow = strdup(optarg);
                break;
            case 'V':
                command_options = command_options | cib_verbose;
                crm_bump_log_level(argc, argv);
                break;
            case '$':
            case '?':
                crm_help(flag, EX_OK);
                break;
            case 'f':
                command_options |= cib_quorum_override;
                force_flag = 1;
                break;
            case 'b':
                batch_flag = 1;
                break;
            default:
                printf("Argument code 0%o (%c)" " is not (?yet?) supported\n", flag, flag);
                ++argerr;
                break;
        }
    }

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

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

    if (argerr) {
        crm_help('?', EX_USAGE);
    }

    if (command == 'w') {
        /* which shadow instance is active? */
        const char *local = getenv("CIB_shadow");

        if (local == NULL) {
            fprintf(stderr, "No shadow instance provided\n");
            rc = -ENXIO;
            goto done;
        }
        fprintf(stdout, "%s\n", local);
        rc = 0;
        goto done;
    }

    if (shadow == NULL) {
        fprintf(stderr, "No shadow instance provided\n");
        fflush(stderr);
        rc = -EINVAL;
        goto done;

    } else if (command != 's' && command != 'c') {
        const char *local = getenv("CIB_shadow");

        if (local != NULL && safe_str_neq(local, shadow) && force_flag == FALSE) {
            fprintf(stderr,
                    "The supplied shadow instance (%s) is not the same as the active one (%s).\n"
                    "  To prevent accidental destruction of the cluster,"
                    " the --force flag is required in order to proceed.\n", shadow, local);
            fflush(stderr);
            rc = EX_USAGE;
            goto done;
        }
    }

    if (dangerous_cmd && force_flag == FALSE) {
        fprintf(stderr, "The supplied command is considered dangerous."
                "  To prevent accidental destruction of the cluster,"
                " the --force flag is required in order to proceed.\n");
        fflush(stderr);
        rc = EX_USAGE;
        goto done;
    }

    shadow_file = get_shadow_file(shadow);
    if (command == 'D') {
        /* delete the file */
        rc = stat(shadow_file, &buf);
        if (rc == 0) {
            rc = unlink(shadow_file);
            if (rc != 0) {
                fprintf(stderr, "Could not remove shadow instance '%s': %s\n", shadow,
                        strerror(errno));
                goto done;
            }
        }

        shadow_teardown(shadow);
        goto done;

    } else if (command == 'F') {
        printf("%s\n", shadow_file);
        rc = 0;
        goto done;
    }

    if (command == 'd' || command == 'r' || command == 'c' || command == 'C') {
        real_cib = cib_new_no_shadow();
        rc = real_cib->cmds->signon(real_cib, crm_system_name, cib_command);
        if (rc != pcmk_ok) {
            fprintf(stderr, "Signon to CIB failed: %s\n", pcmk_strerror(rc));
            goto done;
        }
    }

    rc = stat(shadow_file, &buf);

    if (command == 'e' || command == 'c') {
        if (rc == 0 && force_flag == FALSE) {
            fprintf(stderr, "A shadow instance '%s' already exists.\n"
                    "  To prevent accidental destruction of the cluster,"
                    " the --force flag is required in order to proceed.\n", shadow);
            rc = -ENOTUNIQ;
            goto done;
        }

    } else if (rc != 0) {
        fprintf(stderr, "Could not access shadow instance '%s': %s\n", shadow, strerror(errno));
        rc = -ENXIO;
        goto done;
    }

    rc = pcmk_ok;
    if (command == 'c' || command == 'e' || command == 'r') {
        xmlNode *output = NULL;

        /* create a shadow instance based on the current cluster config */
        if (command == 'c' || command == 'r') {
            rc = real_cib->cmds->query(real_cib, NULL, &output, command_options);
            if (rc != pcmk_ok) {
                fprintf(stderr, "Could not connect to the CIB: %s\n", pcmk_strerror(rc));
                goto done;
            }

        } else {
            output = createEmptyCib(0);
            if(validation) {
                crm_xml_add(output, XML_ATTR_VALIDATION, validation);
            }
            printf("Created new %s configuration\n",
                   crm_element_value(output, XML_ATTR_VALIDATION));
        }

        rc = write_xml_file(output, shadow_file, FALSE);
        free_xml(output);

        if (rc < 0) {
            fprintf(stderr, "Could not %s the shadow instance '%s': %s\n",
                    command == 'r' ? "reset" : "create",
                    shadow, strerror(errno));
            goto done;
        }
        shadow_setup(shadow, FALSE);
        rc = pcmk_ok;

    } else if (command == 'E') {
        const char *err = NULL;
        char *editor = getenv("EDITOR");

        if (editor == NULL) {
            fprintf(stderr, "No value for $EDITOR defined\n");
            rc = -EINVAL;
            goto done;
        }

        execlp(editor, "--", shadow_file, NULL);
        err = strerror(errno);
        fprintf(stderr, "Could not invoke $EDITOR (%s %s): %s\n", editor, shadow_file, err);
        rc = -EINVAL;
        goto done;

    } else if (command == 's') {
        shadow_setup(shadow, TRUE);
        rc = 0;
        goto done;

    } else if (command == 'P') {
        /* display the current contents */
        char *output_s = NULL;
        xmlNode *output = filename2xml(shadow_file);

        output_s = dump_xml_formatted(output);
        printf("%s", output_s);

        free(output_s);
        free_xml(output);

    } else if (command == 'd') {
        /* diff against cluster */
        xmlNode *diff = NULL;
        xmlNode *old_config = NULL;
        xmlNode *new_config = filename2xml(shadow_file);

        rc = real_cib->cmds->query(real_cib, NULL, &old_config, command_options);

        if (rc != pcmk_ok) {
            fprintf(stderr, "Could not query the CIB: %s\n", pcmk_strerror(rc));
            goto done;
        }

        diff = xml_create_patchset(0, old_config, new_config, NULL, FALSE, FALSE);
        if (diff != NULL) {
            xml_log_patchset(0, "  ", diff);
            rc = 1;
            goto done;
        }
        rc = 0;
        goto done;

    } else if (command == 'C') {
        /* commit to the cluster */
        xmlNode *input = filename2xml(shadow_file);

        if (full_upload) {
            rc = real_cib->cmds->replace(real_cib, NULL, input, command_options);
        } else {
            xmlNode *config = first_named_child(input, XML_CIB_TAG_CONFIGURATION);

            rc = real_cib->cmds->replace(real_cib, XML_CIB_TAG_CONFIGURATION, config,
                                         command_options);
        }

        if (rc != pcmk_ok) {
            fprintf(stderr, "Could not commit shadow instance '%s' to the CIB: %s\n",
                    shadow, pcmk_strerror(rc));
            goto done;
        }
        shadow_teardown(shadow);
        free_xml(input);
    }
  done:
    free(shadow_file);
    free(shadow);
    return crm_exit(rc);
}
Exemplo n.º 4
0
static void
te_legacy_update_diff(const char *event, xmlNode * diff)
{
    int lpc, max;
    xmlXPathObject *xpathObj = NULL;

    CRM_CHECK(diff != NULL, return);

    xml_log_patchset(LOG_TRACE, __FUNCTION__, diff);
    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 (numXpathResults(xpathObj) > 0) {
        xmlNode *aborted = getXpathResult(xpathObj, 0);

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

    }
    freeXpathObject(xpathObj);

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

        abort_transition(INFINITY, tg_restart, "Ticket attribute: removal", aborted);
        goto bail;
    }
    freeXpathObject(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);
    max = numXpathResults(xpathObj);

    for (lpc = 0; lpc < max; 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;
        }
    }

    freeXpathObject(xpathObj);

    /* Transient Attributes - Removed */
    xpathObj =
        xpath_search(diff,
                     "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//"
                     XML_TAG_TRANSIENT_NODEATTRS);
    if (numXpathResults(xpathObj) > 0) {
        xmlNode *aborted = getXpathResult(xpathObj, 0);

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

    }
    freeXpathObject(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);
    }

    max = numXpathResults(xpathObj);
    if (max > 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", max);
        crm_log_xml_trace(diff, "lrm-refresh");
        abort_transition(INFINITY, tg_restart, "LRM Refresh", NULL);
        goto bail;
    }
    freeXpathObject(xpathObj);

    /* Process operation updates */
    xpathObj =
        xpath_search(diff,
                     "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_LRM_TAG_RSC_OP);
    if (numXpathResults(xpathObj)) {
/*
    <status>
       <node_state id="node1" state=CRMD_JOINSTATE_MEMBER exp_state="active">
          <lrm>
             <lrm_resources>
        	<rsc_state id="" rsc_id="rsc4" node_id="node1" rsc_state="stopped"/>
*/
        int lpc = 0, max = numXpathResults(xpathObj);

        for (lpc = 0; lpc < max; lpc++) {
            xmlNode *rsc_op = getXpathResult(xpathObj, lpc);
            const char *node = get_node_id(rsc_op);

            process_graph_event(rsc_op, node);
        }
    }
    freeXpathObject(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);
    max = numXpathResults(xpathObj);
    for (lpc = 0; lpc < max; lpc++) {
        int path_max = 0;
        const char *op_id = NULL;
        char *rsc_op_xpath = NULL;
        xmlXPathObject *op_match = NULL;
        xmlNode *match = getXpathResult(xpathObj, lpc);

        CRM_LOG_ASSERT(match != NULL);
        if(match == NULL) { continue; };

        op_id = ID(match);

        path_max = strlen(rsc_op_template) + strlen(op_id) + 1;
        rsc_op_xpath = calloc(1, path_max);
        snprintf(rsc_op_xpath, path_max, rsc_op_template, op_id);

        op_match = xpath_search(diff, rsc_op_xpath);
        if (numXpathResults(op_match) == 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);
                freeXpathObject(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);
            }
        }

        freeXpathObject(op_match);
        free(rsc_op_xpath);
    }

  bail:
    freeXpathObject(xpathObj);
}
Exemplo n.º 5
0
int
main(int argc, char **argv)
{
    gboolean apply = FALSE;
    gboolean raw_1 = FALSE;
    gboolean raw_2 = FALSE;
    gboolean use_stdin = FALSE;
    gboolean as_cib = FALSE;
    int argerr = 0;
    int flag;
    xmlNode *object_1 = NULL;
    xmlNode *object_2 = NULL;
    xmlNode *output = NULL;
    const char *xml_file_1 = NULL;
    const char *xml_file_2 = NULL;

    int option_index = 0;

    crm_log_cli_init("crm_diff");
    crm_set_options(NULL, "original_xml operation [options]", long_options,
                    "A utility for comparing Pacemaker configurations (XML format)\n\n"
                    "The tool produces a custom (diff-like) output which it can also apply like a patch\n");

    if (argc < 2) {
        crm_help('?', EX_USAGE);
    }

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

        switch (flag) {
            case 'o':
                xml_file_1 = optarg;
                break;
            case 'O':
                xml_file_1 = optarg;
                raw_1 = TRUE;
                break;
            case 'n':
                xml_file_2 = optarg;
                break;
            case 'N':
                xml_file_2 = optarg;
                raw_2 = TRUE;
                break;
            case 'p':
                xml_file_2 = optarg;
                apply = TRUE;
                break;
            case 's':
                use_stdin = TRUE;
                break;
            case 'c':
                as_cib = TRUE;
                break;
            case 'V':
                crm_bump_log_level(argc, argv);
                break;
            case '?':
            case '$':
                crm_help(flag, EX_OK);
                break;
            default:
                printf("Argument code 0%o (%c)" " is not (?yet?) supported\n", flag, flag);
                ++argerr;
                break;
        }
    }

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

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

    if (argerr) {
        crm_help('?', EX_USAGE);
    }

    if (raw_1) {
        object_1 = string2xml(xml_file_1);

    } else if (use_stdin) {
        fprintf(stderr, "Input first XML fragment:");
        object_1 = stdin2xml();

    } else if (xml_file_1 != NULL) {
        object_1 = filename2xml(xml_file_1);
    }

    if (raw_2) {
        object_2 = string2xml(xml_file_2);

    } else if (use_stdin) {
        fprintf(stderr, "Input second XML fragment:");
        object_2 = stdin2xml();

    } else if (xml_file_2 != NULL) {
        object_2 = filename2xml(xml_file_2);
    }

    if (object_1 == NULL) {
        fprintf(stderr, "Could not parse the first XML fragment\n");
        return 1;
    }
    if (object_2 == NULL) {
        fprintf(stderr, "Could not parse the second XML fragment\n");
        return 1;
    }

    if (apply) {
        int rc;

        output = copy_xml(object_1);
        rc = xml_apply_patchset(output, object_2, as_cib);
        if(rc != pcmk_ok) {
            fprintf(stderr, "Could not apply patch: %s\n", pcmk_strerror(rc));
            return rc;
        }
    } else {
        xml_track_changes(object_2, NULL, object_2, FALSE);
        xml_calculate_changes(object_1, object_2);
        crm_log_xml_debug(object_2, xml_file_2?xml_file_2:"target");

        output = xml_create_patchset(0, object_1, object_2, NULL, FALSE, as_cib);

        if(as_cib && output) {
            int add[] = { 0, 0, 0 };
            int del[] = { 0, 0, 0 };

            const char *fmt = NULL;
            const char *digest = NULL;

            xml_patch_versions(output, add, del);
            fmt = crm_element_value(output, "format");
            digest = crm_element_value(output, XML_ATTR_DIGEST);

            if (add[2] != del[2] || add[1] != del[1] || add[0] != del[0]) {
                crm_info("Patch: --- %d.%d.%d %s", del[0], del[1], del[2], fmt);
                crm_info("Patch: +++ %d.%d.%d %s", add[0], add[1], add[2], digest);
            }
        }
        xml_log_changes(LOG_INFO, __FUNCTION__, object_2);
        xml_log_patchset(LOG_NOTICE, __FUNCTION__, output);
    }

    if (output != NULL) {
        char *buffer = dump_xml_formatted(output);

        fprintf(stdout, "%s\n", crm_str(buffer));
        free(buffer);

        fflush(stdout);

        if (apply) {
            const char *version = crm_element_value(output, XML_ATTR_CRM_VERSION);

            buffer = calculate_xml_versioned_digest(output, FALSE, TRUE, version);
            crm_trace("Digest: %s\n", crm_str(buffer));
            free(buffer);
        }
    }

    free_xml(object_1);
    free_xml(object_2);
    free_xml(output);

    if (apply == FALSE && output != NULL) {
        return 1;
    }

    return 0;
}
Exemplo n.º 6
0
int
cib_process_command(xmlNode * request, xmlNode ** reply, xmlNode ** cib_diff, gboolean privileged)
{
    xmlNode *input = NULL;
    xmlNode *output = NULL;
    xmlNode *result_cib = NULL;
    xmlNode *current_cib = NULL;

    int call_type = 0;
    int call_options = 0;

    const char *op = NULL;
    const char *section = NULL;
    const char *call_id = crm_element_value(request, F_CIB_CALLID);

    int rc = pcmk_ok;
    int rc2 = pcmk_ok;

    gboolean send_r_notify = FALSE;
    gboolean global_update = FALSE;
    gboolean config_changed = FALSE;
    gboolean manage_counters = TRUE;

    static mainloop_timer_t *digest_timer = NULL;

    CRM_ASSERT(cib_status == pcmk_ok);

    if(digest_timer == NULL) {
        digest_timer = mainloop_timer_add("digester", 5000, FALSE, cib_digester_cb, NULL);
    }

    *reply = NULL;
    *cib_diff = NULL;
    current_cib = the_cib;

    /* Start processing the request... */
    op = crm_element_value(request, F_CIB_OPERATION);
    crm_element_value_int(request, F_CIB_CALLOPTS, &call_options);
    rc = cib_get_operation_id(op, &call_type);

    if (rc == pcmk_ok && privileged == FALSE) {
        rc = cib_op_can_run(call_type, call_options, privileged, global_update);
    }

    rc2 = cib_op_prepare(call_type, request, &input, &section);
    if (rc == pcmk_ok) {
        rc = rc2;
    }

    if (rc != pcmk_ok) {
        crm_trace("Call setup failed: %s", pcmk_strerror(rc));
        goto done;

    } else if (cib_op_modifies(call_type) == FALSE) {
        rc = cib_perform_op(op, call_options, cib_op_func(call_type), TRUE,
                            section, request, input, FALSE, &config_changed,
                            current_cib, &result_cib, NULL, &output);

        CRM_CHECK(result_cib == NULL, free_xml(result_cib));
        goto done;
    }

    /* Handle a valid write action */
    global_update = crm_is_true(crm_element_value(request, F_CIB_GLOBAL_UPDATE));
    if (global_update) {
        /* legacy code */
        manage_counters = FALSE;
        call_options |= cib_force_diff;
        crm_trace("Global update detected");

        CRM_CHECK(call_type == 3 || call_type == 4, crm_err("Call type: %d", call_type);
                  crm_log_xml_err(request, "bad op"));
    }

    if (rc == pcmk_ok) {
        ping_modified_since = TRUE;
        if (call_options & cib_inhibit_bcast) {
            /* skip */
            crm_trace("Skipping update: inhibit broadcast");
            manage_counters = FALSE;
        }

        if (is_not_set(call_options, cib_dryrun) && safe_str_eq(section, XML_CIB_TAG_STATUS)) {
            /* Copying large CIBs accounts for a huge percentage of our CIB usage */
            call_options |= cib_zero_copy;
        } else {
            clear_bit(call_options, cib_zero_copy);
        }

        /* result_cib must not be modified after cib_perform_op() returns */
        rc = cib_perform_op(op, call_options, cib_op_func(call_type), FALSE,
                            section, request, input, manage_counters, &config_changed,
                            current_cib, &result_cib, cib_diff, &output);

        if (manage_counters == FALSE) {
            /* Legacy code
             * If the diff is NULL at this point, its because nothing changed
             */
            config_changed = cib_config_changed(NULL, NULL, cib_diff);
        }

        /* Always write to disk for replace ops,
         * this also negates the need to detect ordering changes
         */
        if (crm_str_eq(CIB_OP_REPLACE, op, TRUE)) {
            config_changed = TRUE;
        }
    }

    if (rc == pcmk_ok && is_not_set(call_options, cib_dryrun)) {
        if(is_not_set(call_options, cib_zero_copy)) {
            rc = activateCibXml(result_cib, config_changed, op);
        }

        if (rc == pcmk_ok && cib_internal_config_changed(*cib_diff)) {
            cib_read_config(config_hash, result_cib);
        }

        if (crm_str_eq(CIB_OP_REPLACE, op, TRUE)) {
            if (section == NULL) {
                send_r_notify = TRUE;

            } else if (safe_str_eq(section, XML_TAG_CIB)) {
                send_r_notify = TRUE;

            } else if (safe_str_eq(section, XML_CIB_TAG_NODES)) {
                send_r_notify = TRUE;

            } else if (safe_str_eq(section, XML_CIB_TAG_STATUS)) {
                send_r_notify = TRUE;
            }

        } else if (crm_str_eq(CIB_OP_ERASE, op, TRUE)) {
            send_r_notify = TRUE;
        }

        mainloop_timer_stop(digest_timer);
        mainloop_timer_start(digest_timer);

    } else if (rc == -pcmk_err_schema_validation) {
        CRM_ASSERT(is_not_set(call_options, cib_zero_copy));

        if (output != NULL) {
            crm_log_xml_info(output, "cib:output");
            free_xml(output);
        }

        output = result_cib;

    } else {
        if(is_not_set(call_options, cib_zero_copy)) {
            free_xml(result_cib);
        }
    }

    if ((call_options & cib_inhibit_notify) == 0) {
        const char *client = crm_element_value(request, F_CIB_CLIENTNAME);

        crm_trace("Sending notifications");
        cib_diff_notify(call_options, client, call_id, op, input, rc, *cib_diff);
    }

    if (send_r_notify) {
        const char *origin = crm_element_value(request, F_ORIG);

        cib_replace_notify(origin, the_cib, rc, *cib_diff);
    }

    xml_log_patchset(LOG_TRACE, "cib:diff", *cib_diff);
  done:
    if ((call_options & cib_discard_reply) == 0) {
        const char *caller = crm_element_value(request, F_CIB_CLIENTID);

        *reply = create_xml_node(NULL, "cib-reply");
        crm_xml_add(*reply, F_TYPE, T_CIB);
        crm_xml_add(*reply, F_CIB_OPERATION, op);
        crm_xml_add(*reply, F_CIB_CALLID, call_id);
        crm_xml_add(*reply, F_CIB_CLIENTID, caller);
        crm_xml_add_int(*reply, F_CIB_CALLOPTS, call_options);
        crm_xml_add_int(*reply, F_CIB_RC, rc);

        if (output != NULL) {
            crm_trace("Attaching reply output");
            add_message_xml(*reply, F_CIB_CALLDATA, output);
        }

        crm_log_xml_explicit(*reply, "cib:reply");
    }

    crm_trace("cleanup");

    if (cib_op_modifies(call_type) == FALSE && output != current_cib) {
        free_xml(output);
        output = NULL;
    }

    if (call_type >= 0) {
        cib_op_cleanup(call_type, call_options, &input, &output);
    }

    crm_trace("done");
    return rc;
}
Exemplo n.º 7
0
int
cib_server_process_diff(const char *op, int options, const char *section, xmlNode * req,
                        xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
                        xmlNode ** answer)
{
    int rc = pcmk_ok;

    if (cib_is_master) {
        /* the master is never waiting for a resync */
        sync_in_progress = 0;
    }

    if (sync_in_progress > MAX_DIFF_RETRY) {
        /* request another full-sync,
         * the last request may have been lost
         */
        sync_in_progress = 0;
    }

    if (sync_in_progress) {
        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;

        cib_diff_version_details(input,
                                 &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
                                 &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);

        sync_in_progress++;
        crm_notice("Not applying diff %d.%d.%d -> %d.%d.%d (sync in progress)",
                   diff_del_admin_epoch, diff_del_epoch, diff_del_updates,
                   diff_add_admin_epoch, diff_add_epoch, diff_add_updates);
        return -pcmk_err_diff_resync;
    }

    rc = cib_process_diff(op, options, section, req, input, existing_cib, result_cib, answer);
    crm_trace("result: %s (%d), %s", pcmk_strerror(rc), rc, cib_is_master?"master":"slave");

    if (rc == -pcmk_err_diff_resync && cib_is_master == FALSE) {
        free_xml(*result_cib);
        *result_cib = NULL;
        send_sync_request(NULL);

    } else if (rc == -pcmk_err_diff_resync) {
        rc = -pcmk_err_diff_failed;
        if (options & cib_force_diff) {
            crm_warn("Not requesting full refresh in R/W mode");
        }

    } else if(rc != pcmk_ok && cib_legacy_mode()) {
        crm_warn("Something went wrong in compatibility mode, requesting full refresh");
        xml_log_patchset(LOG_INFO, __FUNCTION__, input);
        free_xml(*result_cib);
        *result_cib = NULL;
        send_sync_request(NULL);
    }

    return rc;
}