root/tools/cibadmin.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. print_xml_output
  2. report_schema_unchanged
  3. main
  4. do_work
  5. do_init
  6. cibadmin_op_callback

   1 /*
   2  * Copyright 2004-2022 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 #include <stdio.h>
  12 #include <crm/crm.h>
  13 #include <crm/msg_xml.h>
  14 #include <crm/common/xml.h>
  15 #include <crm/common/ipc.h>
  16 #include <crm/cib/internal.h>
  17 
  18 #include <pacemaker-internal.h>
  19 
  20 static int message_timeout_ms = 30;
  21 static int command_options = 0;
  22 static int request_id = 0;
  23 static int bump_log_num = 0;
  24 
  25 static char *host = NULL;
  26 static const char *cib_user = NULL;
  27 static const char *cib_action = NULL;
  28 static const char *obj_type = NULL;
  29 
  30 static cib_t *the_cib = NULL;
  31 static GMainLoop *mainloop = NULL;
  32 static gboolean force_flag = FALSE;
  33 static crm_exit_t exit_code = CRM_EX_OK;
  34 
  35 int do_init(void);
  36 int do_work(xmlNode *input, int command_options, xmlNode **output);
  37 void cibadmin_op_callback(xmlNode *msg, int call_id, int rc, xmlNode *output,
  38                           void *user_data);
  39 
  40 static pcmk__cli_option_t long_options[] = {
  41     // long option, argument type, storage, short option, description, flags
  42     {
  43         "help", no_argument, NULL, '?',
  44         "\tThis text", pcmk__option_default
  45     },
  46     {
  47         "version", no_argument, NULL, '$',
  48         "\tVersion information", pcmk__option_default
  49     },
  50     {
  51         "verbose", no_argument, NULL, 'V',
  52         "\tIncrease debug output\n", pcmk__option_default
  53     },
  54 
  55     {
  56         "-spacer-", no_argument, NULL, '-',
  57         "Commands:", pcmk__option_default
  58     },
  59     {
  60         "upgrade", no_argument, NULL, 'u',
  61         "\tUpgrade the configuration to the latest syntax", pcmk__option_default
  62     },
  63     {
  64         "query", no_argument, NULL, 'Q',
  65         "\tQuery the contents of the CIB", pcmk__option_default
  66     },
  67     {
  68         "erase", no_argument, NULL, 'E',
  69         "\tErase the contents of the whole CIB", pcmk__option_default
  70     },
  71     {
  72         "bump", no_argument, NULL, 'B',
  73         "\tIncrease the CIB's epoch value by 1", pcmk__option_default
  74     },
  75     {
  76         "create", no_argument, NULL, 'C',
  77         "\tCreate an object in the CIB (will fail if object already exists)",
  78         pcmk__option_default
  79     },
  80     {
  81         "modify", no_argument, NULL, 'M',
  82         "\tFind object somewhere in CIB's XML tree and update it "
  83             "(fails if object does not exist unless -c is also specified)",
  84         pcmk__option_default
  85     },
  86     {
  87         "patch", no_argument, NULL, 'P',
  88         "\tSupply an update in the form of an XML diff (see crm_diff(8))",
  89         pcmk__option_default
  90     },
  91     {
  92         "replace", no_argument, NULL, 'R',
  93         "\tRecursively replace an object in the CIB", pcmk__option_default
  94     },
  95     {
  96         "delete", no_argument, NULL, 'D',
  97         "\tDelete first object matching supplied criteria "
  98             "(for example, <op id=\"rsc1_op1\" name=\"monitor\"/>)",
  99         pcmk__option_default
 100     },
 101     {
 102         "-spacer-", no_argument, NULL, '-',
 103         "\n\tThe XML element name and all attributes must match "
 104             "in order for the element to be deleted.\n",
 105         pcmk__option_default
 106     },
 107     {
 108         "delete-all", no_argument, NULL, 'd',
 109         "When used with --xpath, remove all matching objects in the "
 110             "configuration instead of just the first one",
 111         pcmk__option_default
 112     },
 113     {
 114         "empty", no_argument, NULL, 'a',
 115         "\tOutput an empty CIB", pcmk__option_default
 116     },
 117     {
 118         "md5-sum", no_argument, NULL, '5',
 119         "\tCalculate the on-disk CIB digest", pcmk__option_default
 120     },
 121     {
 122         "md5-sum-versioned", no_argument, NULL, '6',
 123         "Calculate an on-the-wire versioned CIB digest", pcmk__option_default
 124     },
 125     {
 126         "show-access", optional_argument, NULL, 'S',
 127         "Whether to use syntax highlighting for ACLs "
 128             "(with -Q/--query and -U/--user)",
 129         pcmk__option_default
 130     },
 131     {
 132         "-spacer-", no_argument, NULL, '-',
 133         "\n\tThat amounts to one of \"color\" (default for terminal),"
 134             " \"text\" (otherwise), \"namespace\", or \"auto\""
 135             " (per former defaults).",
 136         pcmk__option_default
 137     },
 138     {
 139         "blank", no_argument, NULL, '-',
 140         NULL, pcmk__option_hidden
 141     },
 142 
 143     {
 144         "-spacer-", required_argument, NULL, '-',
 145         "\nAdditional options:", pcmk__option_default
 146     },
 147     {
 148         "force", no_argument, NULL, 'f',
 149         NULL, pcmk__option_default
 150     },
 151     {
 152         "timeout", required_argument, NULL, 't',
 153         "Time (in seconds) to wait before declaring the operation failed",
 154         pcmk__option_default
 155     },
 156     {
 157         "user", required_argument, NULL, 'U',
 158         "Run the command with permissions of the named user (valid only for "
 159             "the root and " CRM_DAEMON_USER " accounts)",
 160         pcmk__option_default
 161     },
 162     {
 163         "sync-call", no_argument, NULL, 's',
 164         "Wait for call to complete before returning", pcmk__option_default
 165     },
 166     {
 167         "local", no_argument, NULL, 'l',
 168         "\tCommand takes effect locally (should be used only for queries)",
 169         pcmk__option_default
 170     },
 171     {
 172         "allow-create", no_argument, NULL, 'c',
 173         "(Advanced) Allow target of --modify/-M to be created "
 174             "if it does not exist",
 175         pcmk__option_default
 176     },
 177     {
 178         "no-children", no_argument, NULL, 'n',
 179         "(Advanced) When querying an object, do not include its children "
 180             "in the result",
 181         pcmk__option_default
 182     },
 183     {
 184         "no-bcast", no_argument, NULL, 'b',
 185         NULL, pcmk__option_hidden
 186     },
 187 
 188     {
 189         "-spacer-", no_argument, NULL, '-',
 190         "\nData:", pcmk__option_default
 191     },
 192     {
 193         "xml-text", required_argument, NULL, 'X',
 194         "Retrieve XML from the supplied string", pcmk__option_default
 195     },
 196     {
 197         "xml-file", required_argument, NULL, 'x',
 198         "Retrieve XML from the named file", pcmk__option_default
 199     },
 200     {
 201         "xml-pipe", no_argument, NULL, 'p',
 202         "Retrieve XML from stdin\n", pcmk__option_default
 203     },
 204 
 205     {
 206         "scope", required_argument, NULL, 'o',
 207         "Limit scope of operation to specific section of CIB",
 208         pcmk__option_default
 209     },
 210     {
 211         "-spacer-", no_argument, NULL, '-',
 212         "\tValid values: configuration, nodes, resources, constraints, "
 213             "crm_config, rsc_defaults, op_defaults, acls, fencing-topology, "
 214             "tags, alerts",
 215         pcmk__option_default
 216     },
 217 
 218     {
 219         "xpath", required_argument, NULL, 'A',
 220         "A valid XPath to use instead of --scope/-o", pcmk__option_default
 221     },
 222     {
 223         "node-path", no_argument, NULL, 'e',
 224         "When performing XPath queries, return path of any matches found",
 225         pcmk__option_default
 226     },
 227     {
 228         "-spacer-", no_argument, NULL, '-',
 229         "\t(for example, \"/cib/configuration/resources/clone[@id='ms_RH1_SCS']"
 230             "/primitive[@id='prm_RH1_SCS']\")",
 231         pcmk__option_paragraph
 232     },
 233     {
 234         "node", required_argument, NULL, 'N',
 235         "(Advanced) Send command to the specified host", pcmk__option_default
 236     },
 237     {
 238         "-spacer-", no_argument, NULL, '!',
 239         NULL, pcmk__option_hidden
 240     },
 241     {
 242         "-spacer-", no_argument, NULL, '-',
 243         "\n\nExamples:\n", pcmk__option_default
 244     },
 245     {
 246         "-spacer-", no_argument, NULL, '-',
 247         "Query the configuration from the local node:", pcmk__option_paragraph
 248     },
 249     {
 250         "-spacer-", no_argument, NULL, '-',
 251         " cibadmin --query --local", pcmk__option_example
 252     },
 253 
 254     {
 255         "-spacer-", no_argument, NULL, '-',
 256         "Query just the cluster options configuration:", pcmk__option_paragraph
 257     },
 258     {
 259         "-spacer-", no_argument, NULL, '-',
 260         " cibadmin --query --scope crm_config", pcmk__option_example
 261     },
 262 
 263     {
 264         "-spacer-", no_argument, NULL, '-',
 265         "Query all 'target-role' settings:", pcmk__option_paragraph
 266     },
 267     {
 268         "-spacer-", no_argument, NULL, '-',
 269         " cibadmin --query --xpath \"//nvpair[@name='target-role']\"",
 270         pcmk__option_example
 271     },
 272 
 273     {
 274         "-spacer-", no_argument, NULL, '-',
 275         "Remove all 'is-managed' settings:", pcmk__option_paragraph
 276     },
 277     {
 278         "-spacer-", no_argument, NULL, '-',
 279         " cibadmin --delete-all --xpath \"//nvpair[@name='is-managed']\"",
 280         pcmk__option_example
 281     },
 282 
 283     {
 284         "-spacer-", no_argument, NULL, '-',
 285         "Remove the resource named 'old':", pcmk__option_paragraph
 286     },
 287     {
 288         "-spacer-", no_argument, NULL, '-',
 289         " cibadmin --delete --xml-text '<primitive id=\"old\"/>'",
 290         pcmk__option_example
 291     },
 292     {
 293         "-spacer-", no_argument, NULL, '-',
 294         "Remove all resources from the configuration:", pcmk__option_paragraph
 295     },
 296     {
 297         "-spacer-", no_argument, NULL, '-',
 298         " cibadmin --replace --scope resources --xml-text '<resources/>'",
 299         pcmk__option_example
 300     },
 301     {
 302         "-spacer-", no_argument, NULL, '-',
 303         "Replace complete configuration with contents of $HOME/pacemaker.xml:",
 304         pcmk__option_paragraph
 305     },
 306     {
 307         "-spacer-", no_argument, NULL, '-',
 308         " cibadmin --replace --xml-file $HOME/pacemaker.xml",
 309         pcmk__option_example
 310     },
 311     {
 312         "-spacer-", no_argument, NULL, '-',
 313         "Replace constraints section of configuration with contents of "
 314             "$HOME/constraints.xml:",
 315         pcmk__option_paragraph
 316     },
 317     {
 318         "-spacer-", no_argument, NULL, '-',
 319         " cibadmin --replace --scope constraints --xml-file "
 320             "$HOME/constraints.xml",
 321         pcmk__option_example
 322     },
 323     {
 324         "-spacer-", no_argument, NULL, '-',
 325         "Increase configuration version to prevent old configurations from "
 326             "being loaded accidentally:",
 327         pcmk__option_paragraph
 328     },
 329     {
 330         "-spacer-", no_argument, NULL, '-',
 331         " cibadmin --modify --xml-text '<cib admin_epoch=\"admin_epoch++\"/>'",
 332         pcmk__option_example
 333     },
 334     {
 335         "-spacer-", no_argument, NULL, '-',
 336         "Edit the configuration with your favorite $EDITOR:",
 337         pcmk__option_paragraph
 338     },
 339     {
 340         "-spacer-", no_argument, NULL, '-',
 341         " cibadmin --query > $HOME/local.xml", pcmk__option_example
 342     },
 343     {
 344         "-spacer-", no_argument, NULL, '-',
 345         " $EDITOR $HOME/local.xml", pcmk__option_example
 346     },
 347     {
 348         "-spacer-", no_argument, NULL, '-',
 349         " cibadmin --replace --xml-file $HOME/local.xml", pcmk__option_example
 350     },
 351     {
 352         "-spacer-", no_argument, NULL, '-',
 353         "Assuming terminal, render configuration in color (green for writable, blue for readable, red for denied) to visualize permissions for user tony:",
 354         pcmk__option_paragraph
 355     },
 356     {
 357         "-spacer-", no_argument, NULL, '-',
 358         " cibadmin --show-access=color --query --user tony | less -r",
 359         pcmk__option_example
 360     },
 361     {
 362         "-spacer-", no_argument, NULL, '-',
 363         "SEE ALSO:", pcmk__option_default
 364     },
 365     {
 366         "-spacer-", no_argument, NULL, '-',
 367         " crm(8), pcs(8), crm_shadow(8), crm_diff(8)", pcmk__option_default
 368     },
 369     {
 370         "host", required_argument, NULL, 'h',
 371         "deprecated", pcmk__option_hidden
 372     },
 373     { 0, 0, 0, 0 }
 374 };
 375 
 376 static void
 377 print_xml_output(xmlNode * xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 378 {
 379     char *buffer;
 380 
 381     if (!xml) {
 382         return;
 383     } else if (xml->type != XML_ELEMENT_NODE) {
 384         return;
 385     }
 386 
 387     if (command_options & cib_xpath_address) {
 388         const char *id = crm_element_value(xml, XML_ATTR_ID);
 389 
 390         if (pcmk__str_eq((const char *)xml->name, "xpath-query", pcmk__str_casei)) {
 391             xmlNode *child = NULL;
 392 
 393             for (child = xml->children; child; child = child->next) {
 394                 print_xml_output(child);
 395             }
 396 
 397         } else if (id) {
 398             printf("%s\n", id);
 399         }
 400 
 401     } else {
 402         buffer = dump_xml_formatted(xml);
 403         fprintf(stdout, "%s", crm_str(buffer));
 404         free(buffer);
 405     }
 406 }
 407 
 408 // Upgrade requested but already at latest schema
 409 static void
 410 report_schema_unchanged(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 411 {
 412     const char *err = pcmk_rc_str(pcmk_rc_schema_unchanged);
 413 
 414     crm_info("Upgrade unnecessary: %s\n", err);
 415     printf("Upgrade unnecessary: %s\n", err);
 416     exit_code = CRM_EX_OK;
 417 }
 418 
 419 int
 420 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 421 {
 422     int argerr = 0;
 423     int rc = pcmk_ok;
 424     int flag;
 425     const char *source = NULL;
 426     const char *admin_input_xml = NULL;
 427     const char *admin_input_file = NULL;
 428     gboolean dangerous_cmd = FALSE;
 429     gboolean admin_input_stdin = FALSE;
 430     xmlNode *output = NULL;
 431     xmlNode *input = NULL;
 432     char *username = NULL;
 433     const char *acl_cred = NULL;
 434     enum acl_eval_how {
 435         acl_eval_unused,
 436         acl_eval_auto,
 437         acl_eval_namespace,
 438         acl_eval_text,
 439         acl_eval_color,
 440     } acl_eval_how = acl_eval_unused;
 441 
 442     int option_index = 0;
 443 
 444     pcmk__cli_init_logging("cibadmin", 0);
 445     set_crm_log_level(LOG_CRIT);
 446     pcmk__set_cli_options(NULL, "<command> [options]", long_options,
 447                           "query and edit the Pacemaker configuration");
 448 
 449     if (argc < 2) {
 450         pcmk__cli_help('?', CRM_EX_USAGE);
 451     }
 452 
 453     while (1) {
 454         flag = pcmk__next_cli_option(argc, argv, &option_index, NULL);
 455         if (flag == -1)
 456             break;
 457 
 458         switch (flag) {
 459             case 't':
 460                 message_timeout_ms = atoi(optarg);
 461                 if (message_timeout_ms < 1) {
 462                     message_timeout_ms = 30;
 463                 }
 464                 break;
 465             case 'A':
 466                 obj_type = optarg;
 467                 cib__set_call_options(command_options, crm_system_name,
 468                                       cib_xpath);
 469                 break;
 470             case 'e':
 471                 cib__set_call_options(command_options, crm_system_name,
 472                                       cib_xpath_address);
 473                 break;
 474             case 'u':
 475                 cib_action = CIB_OP_UPGRADE;
 476                 dangerous_cmd = TRUE;
 477                 break;
 478             case 'E':
 479                 cib_action = CIB_OP_ERASE;
 480                 dangerous_cmd = TRUE;
 481                 break;
 482             case 'S':
 483                 if (optarg != NULL) {
 484                     if (!strcmp(optarg, "auto")) {
 485                         acl_eval_how = acl_eval_auto;
 486                     } else if (!strcmp(optarg, "namespace")) {
 487                         acl_eval_how = acl_eval_namespace;
 488                     } else if (!strcmp(optarg, "text")) {
 489                         acl_eval_how = acl_eval_text;
 490                     } else if (!strcmp(optarg, "color")) {
 491                         acl_eval_how = acl_eval_color;
 492                     } else {
 493                         fprintf(stderr, "Unrecognized value for --show-access: \"%s\"\n",
 494                                optarg);
 495                         ++argerr;
 496                     }
 497                 } else {
 498                     acl_eval_how = acl_eval_auto;
 499                 }
 500                 /* XXX this is a workaround until we unify happy paths for
 501                        both a/sync handling; the respective extra code is
 502                        only in sync path now, but does it matter at all for
 503                        query-like request wrt. what blackbox users observe? */
 504                 command_options |= cib_sync_call;
 505                 break;
 506             case 'Q':
 507                 cib_action = CIB_OP_QUERY;
 508                 break;
 509             case 'P':
 510                 cib_action = CIB_OP_APPLY_DIFF;
 511                 break;
 512             case 'U':
 513                 cib_user = optarg;
 514                 break;
 515             case 'M':
 516                 cib_action = CIB_OP_MODIFY;
 517                 break;
 518             case 'R':
 519                 cib_action = CIB_OP_REPLACE;
 520                 break;
 521             case 'C':
 522                 cib_action = CIB_OP_CREATE;
 523                 break;
 524             case 'D':
 525                 cib_action = CIB_OP_DELETE;
 526                 break;
 527             case '5':
 528                 cib_action = "md5-sum";
 529                 break;
 530             case '6':
 531                 cib_action = "md5-sum-versioned";
 532                 break;
 533             case 'c':
 534                 cib__set_call_options(command_options, crm_system_name,
 535                                       cib_can_create);
 536                 break;
 537             case 'n':
 538                 cib__set_call_options(command_options, crm_system_name,
 539                                       cib_no_children);
 540                 break;
 541             case 'B':
 542                 cib_action = CIB_OP_BUMP;
 543                 crm_log_args(argc, argv);
 544                 break;
 545             case 'V':
 546                 cib__set_call_options(command_options, crm_system_name,
 547                                       cib_verbose);
 548                 bump_log_num++;
 549                 break;
 550             case '?':
 551             case '$':
 552             case '!':
 553                 pcmk__cli_help(flag, CRM_EX_OK);
 554                 break;
 555             case 'o':
 556                 crm_trace("Option %c => %s", flag, optarg);
 557                 obj_type = optarg;
 558                 break;
 559             case 'X':
 560                 crm_trace("Option %c => %s", flag, optarg);
 561                 admin_input_xml = optarg;
 562                 crm_log_args(argc, argv);
 563                 break;
 564             case 'x':
 565                 crm_trace("Option %c => %s", flag, optarg);
 566                 admin_input_file = optarg;
 567                 crm_log_args(argc, argv);
 568                 break;
 569             case 'p':
 570                 admin_input_stdin = TRUE;
 571                 crm_log_args(argc, argv);
 572                 break;
 573             case 'N':
 574             case 'h':
 575                 pcmk__str_update(&host, optarg);
 576                 break;
 577             case 'l':
 578                 cib__set_call_options(command_options, crm_system_name,
 579                                       cib_scope_local);
 580                 break;
 581             case 'd':
 582                 cib_action = CIB_OP_DELETE;
 583                 cib__set_call_options(command_options, crm_system_name,
 584                                       cib_multiple);
 585                 dangerous_cmd = TRUE;
 586                 break;
 587             case 'b':
 588                 dangerous_cmd = TRUE;
 589                 cib__set_call_options(command_options, crm_system_name,
 590                                       cib_inhibit_bcast|cib_scope_local);
 591                 break;
 592             case 's':
 593                 cib__set_call_options(command_options, crm_system_name,
 594                                       cib_sync_call);
 595                 break;
 596             case 'f':
 597                 force_flag = TRUE;
 598                 cib__set_call_options(command_options, crm_system_name,
 599                                       cib_quorum_override);
 600                 crm_log_args(argc, argv);
 601                 break;
 602             case 'a':
 603                 output = createEmptyCib(1);
 604                 if (optind < argc) {
 605                     crm_xml_add(output, XML_ATTR_VALIDATION, argv[optind]);
 606                 }
 607                 admin_input_xml = dump_xml_formatted(output);
 608                 fprintf(stdout, "%s\n", crm_str(admin_input_xml));
 609                 crm_exit(CRM_EX_OK);
 610                 break;
 611             default:
 612                 printf("Argument code 0%o (%c)" " is not (?yet?) supported\n", flag, flag);
 613                 ++argerr;
 614                 break;
 615         }
 616     }
 617 
 618     while (bump_log_num > 0) {
 619         crm_bump_log_level(argc, argv);
 620         bump_log_num--;
 621     }
 622 
 623     if (optind < argc) {
 624         printf("non-option ARGV-elements: ");
 625         while (optind < argc)
 626             printf("%s ", argv[optind++]);
 627         printf("\n");
 628         pcmk__cli_help('?', CRM_EX_USAGE);
 629     }
 630 
 631     if (optind > argc || cib_action == NULL) {
 632         ++argerr;
 633     }
 634 
 635     if (argerr) {
 636         pcmk__cli_help('?', CRM_EX_USAGE);
 637     }
 638 
 639     if (dangerous_cmd && force_flag == FALSE) {
 640         fprintf(stderr, "The supplied command is considered dangerous."
 641                 "  To prevent accidental destruction of the cluster,"
 642                 " the --force flag is required in order to proceed.\n");
 643         fflush(stderr);
 644         crm_exit(CRM_EX_UNSAFE);
 645     }
 646 
 647     if (admin_input_file != NULL) {
 648         input = filename2xml(admin_input_file);
 649         source = admin_input_file;
 650 
 651     } else if (admin_input_xml != NULL) {
 652         source = "input string";
 653         input = string2xml(admin_input_xml);
 654 
 655     } else if (admin_input_stdin) {
 656         source = "STDIN";
 657         input = stdin2xml();
 658 
 659     } else if (acl_eval_how != acl_eval_unused) {
 660         username = pcmk__uid2username(geteuid());
 661         if (pcmk_acl_required(username)) {
 662             if (force_flag) {
 663                 fprintf(stderr, "The supplied command can provide skewed"
 664                                  " result since it is run under user that also"
 665                                  " gets guarded per ACLs on their own right."
 666                                  " Continuing since --force flag was"
 667                                  " provided.\n");
 668 
 669             } else {
 670                 fprintf(stderr, "The supplied command can provide skewed"
 671                                  " result since it is run under user that also"
 672                                  " gets guarded per ACLs in their own right."
 673                                  " To accept the risk of such a possible"
 674                                  " distortion (without even knowing it at this"
 675                                  " time), use the --force flag.\n");
 676                 crm_exit(CRM_EX_UNSAFE);
 677             }
 678 
 679         }
 680         free(username);
 681         username = NULL;
 682 
 683         if (cib_user == NULL) {
 684             fprintf(stderr, "The supplied command requires -U user specified.\n");
 685             crm_exit(CRM_EX_USAGE);
 686         }
 687 
 688         /* we already stopped/warned ACL-controlled users about consequences */
 689         acl_cred = cib_user;
 690         cib_user = NULL;
 691     }
 692 
 693     if (input != NULL) {
 694         crm_log_xml_debug(input, "[admin input]");
 695 
 696     } else if (source) {
 697         fprintf(stderr, "Couldn't parse input from %s.\n", source);
 698         crm_exit(CRM_EX_CONFIG);
 699     }
 700 
 701     if (pcmk__str_eq(cib_action, "md5-sum", pcmk__str_casei)) {
 702         char *digest = NULL;
 703 
 704         if (input == NULL) {
 705             fprintf(stderr, "Please supply XML to process with -X, -x or -p\n");
 706             crm_exit(CRM_EX_USAGE);
 707         }
 708 
 709         digest = calculate_on_disk_digest(input);
 710         fprintf(stderr, "Digest: ");
 711         fprintf(stdout, "%s\n", crm_str(digest));
 712         free(digest);
 713         free_xml(input);
 714         crm_exit(CRM_EX_OK);
 715 
 716     } else if (pcmk__str_eq(cib_action, "md5-sum-versioned", pcmk__str_casei)) {
 717         char *digest = NULL;
 718         const char *version = NULL;
 719 
 720         if (input == NULL) {
 721             fprintf(stderr, "Please supply XML to process with -X, -x or -p\n");
 722             crm_exit(CRM_EX_USAGE);
 723         }
 724 
 725         version = crm_element_value(input, XML_ATTR_CRM_VERSION);
 726         digest = calculate_xml_versioned_digest(input, FALSE, TRUE, version);
 727         fprintf(stderr, "Versioned (%s) digest: ", version);
 728         fprintf(stdout, "%s\n", crm_str(digest));
 729         free(digest);
 730         free_xml(input);
 731         crm_exit(CRM_EX_OK);
 732     }
 733 
 734     rc = do_init();
 735     if (rc != pcmk_ok) {
 736         crm_err("Init failed, could not perform requested operations");
 737         fprintf(stderr, "Init failed, could not perform requested operations\n");
 738         free_xml(input);
 739         crm_exit(crm_errno2exit(rc));
 740     }
 741 
 742     rc = do_work(input, command_options, &output);
 743     if (rc > 0) {
 744         /* wait for the reply by creating a mainloop and running it until
 745          * the callbacks are invoked...
 746          */
 747         request_id = rc;
 748 
 749         the_cib->cmds->register_callback(the_cib, request_id, message_timeout_ms, FALSE, NULL,
 750                                          "cibadmin_op_callback", cibadmin_op_callback);
 751 
 752         mainloop = g_main_loop_new(NULL, FALSE);
 753 
 754         crm_trace("%s waiting for reply from the local CIB", crm_system_name);
 755 
 756         crm_info("Starting mainloop");
 757         g_main_loop_run(mainloop);
 758 
 759     } else if ((rc == -pcmk_err_schema_unchanged)
 760                && pcmk__str_eq(cib_action, CIB_OP_UPGRADE, pcmk__str_none)) {
 761         report_schema_unchanged();
 762 
 763     } else if (rc < 0) {
 764         crm_err("Call failed: %s", pcmk_strerror(rc));
 765         fprintf(stderr, "Call failed: %s\n", pcmk_strerror(rc));
 766 
 767         if (rc == -pcmk_err_schema_validation) {
 768             if (pcmk__str_eq(cib_action, CIB_OP_UPGRADE, pcmk__str_none)) {
 769                 xmlNode *obj = NULL;
 770                 int version = 0, rc = 0;
 771 
 772                 rc = the_cib->cmds->query(the_cib, NULL, &obj, command_options);
 773                 if (rc == pcmk_ok) {
 774                     update_validation(&obj, &version, 0, TRUE, FALSE);
 775                 }
 776 
 777             } else if (output) {
 778                 validate_xml_verbose(output);
 779             }
 780         }
 781         exit_code = crm_errno2exit(rc);
 782     }
 783 
 784     if (output != NULL && acl_eval_how != acl_eval_unused) {
 785         xmlDoc *acl_evaled_doc;
 786         rc = pcmk__acl_annotate_permissions(acl_cred, output->doc, &acl_evaled_doc);
 787         if (rc == pcmk_rc_ok) {
 788             enum pcmk__acl_render_how how;
 789             xmlChar *rendered = NULL;
 790             free_xml(output);
 791             switch(acl_eval_how) {
 792                 case acl_eval_text:
 793                     how = pcmk__acl_render_text;
 794                     break;
 795                 case acl_eval_color:
 796                     how = pcmk__acl_render_color;
 797                     break;
 798                 case acl_eval_namespace:
 799                     how = pcmk__acl_render_namespace;
 800                     break;
 801                 default:
 802                     if (/*acl_eval_auto*/ isatty(STDOUT_FILENO)) {
 803                         how = pcmk__acl_render_color;
 804                     } else {
 805                         how = pcmk__acl_render_text;
 806                     }
 807                     break;
 808             }
 809 
 810             if (!pcmk__acl_evaled_render(acl_evaled_doc, how,
 811                                             &rendered)) {
 812                 printf("%s\n", (char *) rendered);
 813                 free(rendered);
 814             } else {
 815                 fprintf(stderr, "Could not render evaluated access\n");
 816                 crm_exit(CRM_EX_CONFIG);
 817             }
 818             output = NULL;
 819         } else {
 820             fprintf(stderr, "Could not evaluate access per request (%s, error: %s)\n", acl_cred, pcmk_rc_str(rc));
 821             crm_exit(CRM_EX_CONFIG);
 822         }
 823     }
 824 
 825     if (output != NULL) {
 826         print_xml_output(output);
 827         free_xml(output);
 828     }
 829 
 830     crm_trace("%s exiting normally", crm_system_name);
 831 
 832     free_xml(input);
 833     rc = cib__clean_up_connection(&the_cib);
 834     if (exit_code == CRM_EX_OK) {
 835         exit_code = pcmk_rc2exitc(rc);
 836     }
 837 
 838     free(host);
 839     crm_exit(exit_code);
 840 }
 841 
 842 int
 843 do_work(xmlNode * input, int call_options, xmlNode ** output)
     /* [previous][next][first][last][top][bottom][index][help] */
 844 {
 845     /* construct the request */
 846     the_cib->call_timeout = message_timeout_ms;
 847     if (strcasecmp(CIB_OP_REPLACE, cib_action) == 0
 848         && pcmk__str_eq(crm_element_name(input), XML_TAG_CIB, pcmk__str_casei)) {
 849         xmlNode *status = pcmk_find_cib_element(input, XML_CIB_TAG_STATUS);
 850 
 851         if (status == NULL) {
 852             create_xml_node(input, XML_CIB_TAG_STATUS);
 853         }
 854     }
 855 
 856     if (cib_action != NULL) {
 857         crm_trace("Passing \"%s\" to variant_op...", cib_action);
 858         return cib_internal_op(the_cib, cib_action, host, obj_type, input, output, call_options, cib_user);
 859 
 860     } else {
 861         crm_err("You must specify an operation");
 862     }
 863     return -EINVAL;
 864 }
 865 
 866 int
 867 do_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 868 {
 869     int rc = pcmk_ok;
 870 
 871     the_cib = cib_new();
 872     rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command);
 873     if (rc != pcmk_ok) {
 874         crm_err("Could not connect to the CIB: %s", pcmk_strerror(rc));
 875         fprintf(stderr, "Could not connect to the CIB: %s\n",
 876                 pcmk_strerror(rc));
 877     }
 878 
 879     return rc;
 880 }
 881 
 882 void
 883 cibadmin_op_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 884 {
 885     exit_code = crm_errno2exit(rc);
 886 
 887     if (rc == -pcmk_err_schema_unchanged) {
 888         report_schema_unchanged();
 889 
 890     } else if (rc != pcmk_ok) {
 891         crm_warn("Call %s failed (%d): %s", cib_action, rc, pcmk_strerror(rc));
 892         fprintf(stderr, "Call %s failed (%d): %s\n", cib_action, rc, pcmk_strerror(rc));
 893         print_xml_output(output);
 894 
 895     } else if (pcmk__str_eq(cib_action, CIB_OP_QUERY, pcmk__str_casei) && output == NULL) {
 896         crm_err("Query returned no output");
 897         crm_log_xml_err(msg, "no output");
 898 
 899     } else if (output == NULL) {
 900         crm_info("Call passed");
 901 
 902     } else {
 903         crm_info("Call passed");
 904         print_xml_output(output);
 905     }
 906 
 907     if (call_id == request_id) {
 908         g_main_loop_quit(mainloop);
 909 
 910     } else {
 911         crm_info("Message was not the response we were looking for (%d vs. %d)",
 912                  call_id, request_id);
 913     }
 914 }

/* [previous][next][first][last][top][bottom][index][help] */