diff --git a/crm/admin/crm_attribute.c b/crm/admin/crm_attribute.c index 3dab8561ec..0d8d7de051 100644 --- a/crm/admin/crm_attribute.c +++ b/crm/admin/crm_attribute.c @@ -1,460 +1,466 @@ /* $Id: crm_attribute.c,v 1.18 2006/06/01 16:05:59 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_GETOPT_H # include #endif #include void usage(const char *cmd, int exit_status); gboolean BE_QUIET = FALSE; gboolean DO_WRITE = TRUE; gboolean DO_DELETE = FALSE; gboolean inhibit_pe = FALSE; char *dest_node = NULL; char *set_name = NULL; char *attr_id = NULL; char *attr_name = NULL; const char *type = NULL; const char *rsc_id = NULL; const char *dest_uname = NULL; const char *attr_value = NULL; const char *crm_system_name = "crm_master"; #define OPTARGS "V?GDQU:u:s:n:v:l:t:i:!r:" int main(int argc, char **argv) { gboolean is_done = FALSE; cib_t * the_cib = NULL; enum cib_errors rc = cib_ok; int argerr = 0; int flag; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"quiet", 0, 0, 'Q'}, {"get-value", 0, 0, 'G'}, {"delete-attr", 0, 0, 'D'}, {"node-uname", 1, 0, 'U'}, {"node-uuid", 1, 0, 'u'}, {"set-name", 1, 0, 's'}, {"attr-name", 1, 0, 'n'}, {"attr-value", 1, 0, 'v'}, {"resource-id", 1, 0, 'r'}, {"lifetime", 1, 0, 'l'}, {"inhibit-policy-engine", 0, 0, '!'}, {"type", 1, 0, 't'}, {0, 0, 0, 0} }; #endif crm_system_name = basename(argv[0]); crm_log_init(crm_system_name); crm_log_level = LOG_ERR; cl_log_enable_stderr(TRUE); if(argc < 2) { usage(crm_system_name, LSB_EXIT_EINVAL); } while (1) { #ifdef HAVE_GETOPT_H flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); #else flag = getopt(argc, argv, OPTARGS); #endif if (flag == -1) break; switch(flag) { case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'G': DO_WRITE = FALSE; break; case 'Q': BE_QUIET = TRUE; break; case 'D': DO_DELETE = TRUE; break; case 'U': crm_debug_2("Option %c => %s", flag, optarg); dest_uname = optarg; break; case 'u': crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 's': crm_debug_2("Option %c => %s", flag, optarg); set_name = crm_strdup(optarg); break; case 'l': crm_debug_2("Option %c => %s", flag, optarg); type = optarg; break; case 't': crm_debug_2("Option %c => %s", flag, optarg); type = optarg; break; case 'n': crm_debug_2("Option %c => %s", flag, optarg); attr_name = crm_strdup(optarg); break; case 'i': crm_debug_2("Option %c => %s", flag, optarg); attr_id = crm_strdup(optarg); break; case 'v': crm_debug_2("Option %c => %s", flag, optarg); attr_value = optarg; break; case 'r': crm_debug_2("Option %c => %s", flag, optarg); rsc_id = optarg; break; case '!': inhibit_pe = TRUE; 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) { usage(crm_system_name, LSB_EXIT_GENERIC); } the_cib = cib_new(); rc = the_cib->cmds->signon( the_cib, crm_system_name, cib_command_synchronous); if(rc != cib_ok) { fprintf(stderr, "Error signing on to the CIB service: %s\n", cib_error2string(rc)); return rc; } if(safe_str_eq(crm_system_name, "crm_master")) { struct utsname name; if(uname(&name) != 0) { cl_perror("uname(3) call failed"); return 1; } dest_uname = name.nodename; crm_info("Detected: %s", dest_uname); } if(dest_node == NULL && dest_uname != NULL) { rc = query_node_uuid(the_cib, dest_uname, &dest_node); if(rc != cib_ok) { fprintf(stderr,"Could not map uname=%s to a UUID: %s\n", dest_uname, cib_error2string(rc)); return rc; } else { crm_info("Mapped %s to %s", dest_uname, crm_str(dest_node)); } } if(safe_str_eq(crm_system_name, "crm_master")) { int len = 0; if(safe_str_eq(type, "reboot")) { type = XML_CIB_TAG_STATUS; } else { type = XML_CIB_TAG_NODES; } rsc_id = getenv("OCF_RESOURCE_INSTANCE"); if(rsc_id == NULL && dest_node == NULL) { fprintf(stderr, "This program should only ever be " "invoked from inside an OCF resource agent.\n"); fprintf(stderr, "DO NOT INVOKE MANUALLY FROM THE COMMAND LINE.\n"); return 1; } else if(dest_node == NULL) { fprintf(stderr, "Could not determin node UUID.\n"); return 1; } else if(rsc_id == NULL) { fprintf(stderr, "Could not determin resource name.\n"); return 1; } len = 8 + strlen(rsc_id); crm_malloc0(attr_name, len); sprintf(attr_name, "master-%s", rsc_id); len = 2 + strlen(attr_name) + strlen(dest_node); crm_malloc0(attr_id, len); sprintf(attr_id, "%s-%s", attr_name, dest_node); len = 8 + strlen(dest_node); crm_malloc0(set_name, len); sprintf(set_name, "master-%s", dest_node); } else if(safe_str_eq(crm_system_name, "crm_failcount")) { type = XML_CIB_TAG_STATUS; if(rsc_id == NULL) { fprintf(stderr,"Please specify a resource with -r\n"); return 1; } if(dest_node == NULL) { fprintf(stderr,"Please specify a node with -U or -u\n"); return 1; } set_name = NULL; attr_name = crm_concat("fail-count", rsc_id, '-'); } else if(safe_str_eq(crm_system_name, "crm_standby")) { if(dest_node == NULL) { fprintf(stderr,"Please specify a node with -U or -u\n"); return 1; } else if(DO_DELETE) { rc = delete_standby( the_cib, dest_node, type, attr_value); } else if(DO_WRITE) { if(attr_value == NULL) { fprintf(stderr, "Please specify 'true' or 'false' with -v\n"); return 1; } rc = set_standby(the_cib, dest_node, type, attr_value); } else { char *read_value = NULL; + char *scope = crm_strdup(type); rc = query_standby( - the_cib, dest_node, type, &read_value); + the_cib, dest_node, &scope, &read_value); if(BE_QUIET == FALSE) { - fprintf(stdout, "%s%s %s%s value=%s\n", - attr_id?"id=":"", attr_id?attr_id:"", - attr_name?"name=":"", attr_name?attr_name:"", - read_value?read_value:"(null)"); + if(attr_id) { + fprintf(stdout, "id=%s ", attr_id); + } + if(attr_name) { + fprintf(stdout, "name=%s ", attr_name); + } + fprintf(stdout, "scope=%s value=%s\n", + scope, read_value?read_value:"(null)"); } else if(read_value != NULL) { fprintf(stdout, "%s\n", read_value); } + crm_free(scope); } is_done = TRUE; } else if(type == NULL && dest_node == NULL) { type = XML_CIB_TAG_CRMCONFIG; } else if (type == NULL) { fprintf(stderr, "Please specify a value for -t\n"); return 1; } if(is_done) { } else if(DO_DELETE) { rc = delete_attr(the_cib, cib_sync_call, type, dest_node, set_name, attr_id, attr_name, attr_value); if(safe_str_eq(crm_system_name, "crm_failcount")) { char *now_s = NULL; time_t now = time(NULL); now_s = crm_itoa(now); update_attr(the_cib, cib_sync_call, XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL, "last-lrm-refresh", now_s); crm_free(now_s); } } else if(DO_WRITE) { int cib_opts = cib_sync_call; CRM_DEV_ASSERT(type != NULL); CRM_DEV_ASSERT(attr_name != NULL); CRM_DEV_ASSERT(attr_value != NULL); if(inhibit_pe) { crm_warn("Inhibiting notifications for this update"); cib_opts |= cib_inhibit_notify; } rc = update_attr(the_cib, cib_opts, type, dest_node, set_name, attr_id, attr_name, attr_value); } else { char *read_value = NULL; rc = read_attr(the_cib, type, dest_node, set_name, attr_id, attr_name, &read_value); crm_info("Read %s=%s %s%s", attr_name, crm_str(read_value), set_name?"in ":"", set_name?set_name:""); if(BE_QUIET == FALSE) { fprintf(stdout, "%s%s %s%s value=%s\n", attr_id?"id=":"", attr_id?attr_id:"", attr_name?"name=":"", attr_name?attr_name:"", read_value?read_value:"(null)"); } else if(read_value != NULL) { fprintf(stdout, "%s\n", read_value); } } the_cib->cmds->signoff(the_cib); if(DO_WRITE == FALSE && rc == cib_NOTEXISTS) { fprintf(stderr, "Error performing operation: %s\n", cib_error2string(rc)); } else if(rc != cib_ok) { fprintf(stderr, "Error performing operation: %s\n", cib_error2string(rc)); } return rc; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; if(safe_str_eq(cmd, "crm_master")) { fprintf(stream, "usage: %s [-?VQ] -(D|G|v) [-l]\n", cmd); } else if(safe_str_eq(cmd, "crm_standby")) { fprintf(stream, "usage: %s [-?V] -(u|U) -(D|G|v) [-l]\n", cmd); } else if(safe_str_eq(cmd, "crm_failcount")) { fprintf(stream, "usage: %s [-?V] -(u|U) -(D|G|v) -r\n", cmd); } else { fprintf(stream, "usage: %s [-?V] -(D|G|v) [options]\n", cmd); } fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?'); fprintf(stream, "\t--%s (-%c)\t: " "turn on debug info. additional instances increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\t: Print only the value on stdout" " (use with -G)\n", "quiet", 'Q'); fprintf(stream, "\t--%s (-%c)\t: " "Retrieve rather than set the %s\n", "get-value", 'G', safe_str_eq(cmd, "crm_master")?"named attribute":"preference to be promoted"); fprintf(stream, "\t--%s (-%c)\t: " "Delete rather than set the attribute\n", "delete-attr", 'D'); fprintf(stream, "\t--%s (-%c) \t: " "Value to use (ignored with -G)\n", "attr-value", 'v'); if(safe_str_eq(cmd, "crm_master")) { fprintf(stream, "\t--%s (-%c) \t: " "How long the preference lasts (reboot|forever)\n", "lifetime", 'l'); exit(exit_status); } else if(safe_str_eq(cmd, "crm_standby")) { fprintf(stream, "\t--%s (-%c) \t: " "UUID of the node to change\n", "node-uuid", 'u'); fprintf(stream, "\t--%s (-%c) \t: " "uname of the node to change\n", "node-uname", 'U'); fprintf(stream, "\t--%s (-%c) \t: " "How long the preference lasts (reboot|forever)\n" "\t If a forever value exists, it is ALWAYS used by the CRM\n" "\t instead of any reboot value\n", "lifetime", 'l'); exit(exit_status); } fprintf(stream, "\t--%s (-%c) \t: " "UUID of the node to change\n", "node-uuid", 'u'); fprintf(stream, "\t--%s (-%c) \t: " "uname of the node to change\n", "node-uname", 'U'); if(safe_str_eq(cmd, "crm_failcount")) { fprintf(stream, "\t--%s (-%c) \t: " "name of the resource to operate on\n", "resource-id", 'r'); } else { fprintf(stream, "\t--%s (-%c) \t: " "Set of attributes in which to read/write the attribute\n", "set-name", 's'); fprintf(stream, "\t--%s (-%c) \t: " "Attribute to set\n", "attr-name", 'n'); fprintf(stream, "\t--%s (-%c) \t: " "Which section of the CIB to set the attribute: (%s|%s|%s)\n", "type", 't', XML_CIB_TAG_NODES, XML_CIB_TAG_STATUS, XML_CIB_TAG_CRMCONFIG); fprintf(stream, "\t -t=%s options: -(U|u) -n [-s]\n", XML_CIB_TAG_NODES); fprintf(stream, "\t -t=%s options: -(U|u) -n [-s]\n", XML_CIB_TAG_STATUS); fprintf(stream, "\t -t=%s options: -n [-s]\n", XML_CIB_TAG_CRMCONFIG); } fflush(stream); exit(exit_status); } diff --git a/include/crm/cib.h b/include/crm/cib.h index 3d7139e591..d723000c18 100644 --- a/include/crm/cib.h +++ b/include/crm/cib.h @@ -1,403 +1,402 @@ /* $Id: cib.h,v 1.43 2006/06/22 15:11:56 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef CIB__H #define CIB__H #include #include #include #include #include #define CIB_FEATURE_SET "1.3" #define USE_PESKY_FRAGMENTS 1 #define CIB_OPTIONS_FIRST "cib-bootstrap-options" /* use compare_version() for doing comparisons */ enum cib_variant { cib_native, cib_database, cib_edir }; enum cib_state { cib_connected_command, cib_connected_query, cib_disconnected }; enum cib_conn_type { cib_command, cib_query, cib_query_synchronous, cib_command_synchronous, cib_no_connection }; enum cib_call_options { cib_none = 0x00000000, cib_verbose = 0x00000001, cib_discard_reply = 0x00000010, cib_scope_local = 0x00000100, cib_sync_call = 0x00001000, cib_inhibit_notify = 0x00010000, cib_quorum_override = 0x00100000, cib_inhibit_bcast = 0x01000000, cib_force_diff = 0x10000000 }; #define cib_default_options = cib_none enum cib_errors { cib_ok = 0, cib_operation = -1, cib_create_msg = -2, cib_not_connected = -3, cib_not_authorized = -4, cib_send_failed = -5, cib_reply_failed = -6, cib_return_code = -7, cib_output_ptr = -8, cib_output_data = -9, cib_connection = -10, cib_authentication = -11, cib_missing = -12, cib_variant = -28, CIBRES_MISSING_ID = -13, CIBRES_MISSING_TYPE = -14, CIBRES_MISSING_FIELD = -15, CIBRES_OBJTYPE_MISMATCH = -16, CIBRES_CORRUPT = -17, CIBRES_OTHER = -18, cib_unknown = -19, cib_STALE = -20, cib_EXISTS = -21, cib_NOTEXISTS = -22, cib_ACTIVATION = -23, cib_NOSECTION = -24, cib_NOOBJECT = -25, cib_NOPARENT = -26, cib_NODECOPY = -27, cib_NOTSUPPORTED = -29, cib_registration_msg = -30, cib_callback_token = -31, cib_callback_register = -32, cib_msg_field_add = -33, cib_client_gone = -34, cib_not_master = -35, cib_client_corrupt = -36, cib_master_timeout = -37, cib_revision_unsupported= -38, cib_revision_unknown = -39, cib_missing_data = -40, cib_remote_timeout = -41, cib_no_quorum = -42, cib_diff_failed = -43, cib_diff_resync = -44, cib_old_data = -45, cib_id_check = -46, cib_dtd_validation = -47, cib_bad_section = -48, cib_bad_digest = -49, cib_bad_permissions = -50, cib_bad_config = -51 }; enum cib_update_op { CIB_UPDATE_OP_NONE = 0, CIB_UPDATE_OP_ADD, CIB_UPDATE_OP_MODIFY, CIB_UPDATE_OP_DELETE, CIB_UPDATE_OP_MAX }; enum cib_section { cib_section_none, cib_section_all, cib_section_nodes, cib_section_constraints, cib_section_resources, cib_section_crmconfig, cib_section_status }; #define CIB_OP_SLAVE "cib_slave" #define CIB_OP_SLAVEALL "cib_slave_all" #define CIB_OP_MASTER "cib_master" #define CIB_OP_SYNC "cib_sync" #define CIB_OP_SYNC_ONE "cib_sync_one" #define CIB_OP_ISMASTER "cib_ismaster" #define CIB_OP_BUMP "cib_bump" #define CIB_OP_QUERY "cib_query" #define CIB_OP_CREATE "cib_create" #define CIB_OP_UPDATE "cib_update" #define CIB_OP_MODIFY "cib_modify" #define CIB_OP_DELETE "cib_delete" #define CIB_OP_DELETE_ALT "cib_delete_alt" #define CIB_OP_ERASE "cib_erase" #define CIB_OP_REPLACE "cib_replace" #define CIB_OP_NOTIFY "cib_notify" #define CIB_OP_APPLY_DIFF "cib_apply_diff" #define F_CIB_CLIENTID "cib_clientid" #define F_CIB_CALLOPTS "cib_callopt" #define F_CIB_CALLID "cib_callid" #define F_CIB_CALLDATA "cib_calldata" #define F_CIB_OPERATION "cib_op" #define F_CIB_ISREPLY "cib_isreplyto" #define F_CIB_SECTION "cib_section" #define F_CIB_HOST "cib_host" #define F_CIB_RC "cib_rc" #define F_CIB_DELEGATED "cib_delegated_from" #define F_CIB_OBJID "cib_object" #define F_CIB_OBJTYPE "cib_object_type" #define F_CIB_EXISTING "cib_existing_object" #define F_CIB_SEENCOUNT "cib_seen" #define F_CIB_TIMEOUT "cib_timeout" #define F_CIB_UPDATE "cib_update" #define F_CIB_CALLBACK_TOKEN "cib_callback_token" #define F_CIB_GLOBAL_UPDATE "cib_update" #define F_CIB_UPDATE_RESULT "cib_update_result" #define F_CIB_CLIENTNAME "cib_clientname" #define F_CIB_NOTIFY_TYPE "cib_notify_type" #define F_CIB_NOTIFY_ACTIVATE "cib_notify_activate" #define F_CIB_UPDATE_DIFF "cib_update_diff" #define T_CIB "cib" #define T_CIB_NOTIFY "cib_notify" /* notify sub-types */ #define T_CIB_PRE_NOTIFY "cib_pre_notify" #define T_CIB_POST_NOTIFY "cib_post_notify" #define T_CIB_UPDATE_CONFIRM "cib_update_confirmation" #define T_CIB_DIFF_NOTIFY "cib_diff_notify" #define T_CIB_REPLACE_NOTIFY "cib_refresh_notify" #define cib_channel_ro "cib_ro" #define cib_channel_rw "cib_rw" #define cib_channel_callback "cib_callback" #define cib_channel_ro_synchronous "cib_ro_syncronous" #define cib_channel_rw_synchronous "cib_rw_syncronous" typedef struct cib_s cib_t; typedef struct cib_api_operations_s { int (*variant_op)( cib_t *cib, const char *op, const char *host, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options); int (*signon) ( cib_t *cib, const char *name, enum cib_conn_type type); int (*signoff)(cib_t *cib); int (*free) (cib_t *cib); int (*set_op_callback)( cib_t *cib, void (*callback)( const HA_Message *msg, int callid , int rc, crm_data_t *output)); int (*add_notify_callback)( cib_t *cib, const char *event, void (*callback)( const char *event, HA_Message *msg)); int (*del_notify_callback)( cib_t *cib, const char *event, void (*callback)( const char *event, HA_Message *msg)); int (*set_connection_dnotify)( cib_t *cib, void (*dnotify)(gpointer user_data)); IPC_Channel *(*channel)(cib_t* cib); int (*inputfd)(cib_t* cib); int (*noop)(cib_t *cib, int call_options); int (*ping)( cib_t *cib, crm_data_t **output_data, int call_options); int (*query)(cib_t *cib, const char *section, crm_data_t **output_data, int call_options); int (*query_from)( cib_t *cib, const char *host, const char *section, crm_data_t **output_data, int call_options); int (*is_master) (cib_t *cib); int (*set_master)(cib_t *cib, int call_options); int (*set_slave) (cib_t *cib, int call_options); int (*set_slave_all)(cib_t *cib, int call_options); int (*sync)(cib_t *cib, const char *section, int call_options); int (*sync_from)( cib_t *cib, const char *host, const char *section, int call_options); int (*bump_epoch)(cib_t *cib, int call_options); int (*create)(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options); int (*modify)(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options); int (*update)(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options); int (*replace)(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options); int (*delete)(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options); int (*delete_absolute)( cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options); int (*erase)( cib_t *cib, crm_data_t **output_data, int call_options); int (*quit)(cib_t *cib, int call_options); gboolean (*msgready)(cib_t* cib); int (*rcvmsg)(cib_t* cib, int blocking); gboolean (*dispatch)(IPC_Channel *channel, gpointer user_data); int (*register_callback)( cib_t* cib, const char *callback, int enabled); } cib_api_operations_t; struct cib_s { enum cib_state state; enum cib_conn_type type; int call_id; int call_timeout; void *variant_opaque; GList *notify_list; void (*op_callback)(const HA_Message *msg, int call_id, int rc, crm_data_t *output); cib_api_operations_t *cmds; }; typedef struct cib_notify_client_s { const char *event; const char *obj_id; /* implement one day */ const char *obj_type; /* implement one day */ void (*callback)( const char *event, HA_Message *msg); } cib_notify_client_t; typedef struct cib_callback_client_s { void (*callback)( const HA_Message*, int, int, crm_data_t*, void*); void *user_data; gboolean only_success; } cib_callback_client_t; /* Core functions */ extern cib_t *cib_new(void); extern void cib_delete(cib_t *cib); extern gboolean startCib(const char *filename); extern crm_data_t *get_cib_copy(cib_t *cib); extern crm_data_t *cib_get_generation(cib_t *cib); extern int cib_compare_generation(crm_data_t *left, crm_data_t *right); extern gboolean add_cib_op_callback( int call_id, gboolean only_success, void *user_data, void (*callback)(const HA_Message*, int, int, crm_data_t*,void*)); extern void remove_cib_op_callback(int call_id, gboolean all_callbacks); extern int num_cib_op_callbacks(void); /* Utility functions */ extern crm_data_t *get_object_root(const char *object_type,crm_data_t *the_root); extern crm_data_t *create_cib_fragment_adv( crm_data_t *update, const char *section, const char *source); extern char *cib_pluralSection(const char *a_section); extern const char *get_crm_option( crm_data_t *cib, const char *name, gboolean do_warn); /* Error Interpretation*/ extern const char *cib_error2string(enum cib_errors); extern const char *cib_op2string(enum cib_update_op); extern crm_data_t *createEmptyCib(void); extern gboolean verifyCibXml(crm_data_t *cib); extern int cib_section2enum(const char *a_section); #define create_cib_fragment(update,cib_section) create_cib_fragment_adv(update, cib_section, __FUNCTION__) extern crm_data_t *diff_cib_object( crm_data_t *old, crm_data_t *new,gboolean suppress); extern gboolean apply_cib_diff( crm_data_t *old, crm_data_t *diff, crm_data_t **new); extern void log_cib_diff(int log_level, crm_data_t *diff, const char *function); extern gboolean cib_diff_version_details( crm_data_t *diff, int *admin_epoch, int *epoch, int *updates, int *_admin_epoch, int *_epoch, int *_updates); extern gboolean cib_version_details( crm_data_t *cib, int *admin_epoch, int *epoch, int *updates); extern enum cib_errors update_attr( cib_t *the_cib, int call_options, const char *section, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, const char *attr_value); extern crm_data_t *find_attr_details(crm_data_t *xml_search, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name); extern enum cib_errors read_attr( cib_t *the_cib, const char *section, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, char **attr_value); extern enum cib_errors delete_attr( cib_t *the_cib, int options, const char *section, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, const char *attr_value); extern enum cib_errors query_node_uuid( cib_t *the_cib, const char *uname, char **uuid); extern enum cib_errors query_node_uname( cib_t *the_cib, const char *uuid, char **uname); -extern enum cib_errors query_standby( - cib_t *the_cib, - const char *uuid, const char *scope, char **standby_value); +extern enum cib_errors query_standby(cib_t *the_cib, const char *uuid, + char **scope, char **standby_value); extern enum cib_errors set_standby( cib_t *the_cib, const char *uuid, const char *scope, const char *standby_value); enum cib_errors delete_standby( cib_t *the_cib, const char *uuid, const char *scope, const char *standby_value); extern const char *feature_set(crm_data_t *xml_obj); #endif diff --git a/lib/crm/cib/cib_attrs.c b/lib/crm/cib/cib_attrs.c index 174801156d..38048c9b6e 100644 --- a/lib/crm/cib/cib_attrs.c +++ b/lib/crm/cib/cib_attrs.c @@ -1,630 +1,634 @@ /* $Id: cib_attrs.c,v 1.24 2006/04/18 11:28:56 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define attr_common_setup(section) \ gboolean is_crm_config = FALSE; \ gboolean is_node_transient = FALSE; \ char *local_set_name = NULL; \ if(attr_id == NULL && attr_name == NULL) { \ return cib_missing; \ \ } else if(safe_str_eq(section, XML_CIB_TAG_CRMCONFIG)) { \ tag = NULL; \ is_crm_config = TRUE; \ if(set_name == NULL) { \ set_name = CIB_OPTIONS_FIRST; \ } \ \ } else if(safe_str_eq(section, XML_CIB_TAG_NODES)) { \ tag = XML_CIB_TAG_NODE; \ if(node_uuid == NULL) { \ return cib_missing; \ } \ if(set_name == NULL) { \ local_set_name = crm_concat(section, node_uuid, '-'); \ set_name = local_set_name; \ } \ \ } else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) { \ is_node_transient = TRUE; \ tag = XML_TAG_TRANSIENT_NODEATTRS; \ if(set_name == NULL) { \ local_set_name = crm_concat(section, node_uuid, '-'); \ set_name = local_set_name; \ } \ \ } else { \ return cib_bad_section; \ } \ \ if(attr_id == NULL) { \ local_attr_id = crm_concat(set_name, attr_name, '-'); \ attr_id = local_attr_id; \ \ } else if(attr_name == NULL) { \ attr_name = attr_id; \ } \ crm_data_t * find_attr_details(crm_data_t *xml_search, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name) { int matches = 0; crm_data_t *nv_children = NULL; crm_data_t *set_children = NULL; const char *set_type = XML_TAG_ATTR_SETS; if(node_uuid != NULL) { set_type = XML_CIB_TAG_PROPSET; /* filter by node */ matches = find_xml_children( &set_children, xml_search, NULL, XML_ATTR_ID, node_uuid, FALSE); crm_log_xml_debug(set_children, "search by node:"); if(matches == 0) { crm_info("No node matching id=%s in %s", node_uuid, TYPE(xml_search)); return NULL; } } /* filter by set name */ if(set_name != NULL) { matches = find_xml_children( &set_children, set_children?set_children:xml_search, XML_TAG_ATTR_SETS, XML_ATTR_ID, set_name, FALSE); crm_log_xml_debug(set_children, "search by set:"); if(matches == 0) { crm_info("No set matching id=%s in %s", set_name, TYPE(xml_search)); return NULL; } } matches = 0; if(attr_id == NULL) { matches = find_xml_children( &nv_children, set_children?set_children:xml_search, XML_CIB_TAG_NVPAIR, XML_NVPAIR_ATTR_NAME, attr_name, FALSE); crm_log_xml_debug(nv_children, "search by name:"); } else if(attr_id != NULL) { matches = find_xml_children( &nv_children, set_children?set_children:xml_search, XML_CIB_TAG_NVPAIR, XML_ATTR_ID, attr_id, FALSE); crm_log_xml_debug(nv_children, "search by id:"); } if(matches == 1) { crm_data_t *single_match = NULL; xml_child_iter(nv_children, child, single_match = copy_xml(child); break; ); free_xml(nv_children); return single_match; } else if(matches > 1) { crm_err("Multiple attributes match name=%s in %s:\n", attr_name, TYPE(xml_search)); if(set_children == NULL) { free_xml(set_children); set_children = NULL; find_xml_children( &set_children, xml_search, XML_TAG_ATTR_SETS, NULL, NULL, FALSE); xml_child_iter( set_children, set, free_xml(nv_children); nv_children = NULL; find_xml_children( &nv_children, set, XML_CIB_TAG_NVPAIR, XML_NVPAIR_ATTR_NAME, attr_name, FALSE); xml_child_iter( nv_children, child, crm_info(" Set: %s,\tValue: %s,\tID: %s\n", ID(set), crm_element_value(child, XML_NVPAIR_ATTR_VALUE), ID(child)); ); ); } else { xml_child_iter( nv_children, child, crm_info(" ID: %s, Value: %s\n", ID(child), crm_element_value(child, XML_NVPAIR_ATTR_VALUE)); ); } } return NULL; } enum cib_errors update_attr(cib_t *the_cib, int call_options, const char *section, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, const char *attr_value) { const char *tag = NULL; enum cib_errors rc = cib_ok; crm_data_t *xml_top = NULL; crm_data_t *xml_obj = NULL; crm_data_t *xml_search = NULL; char *local_attr_id = NULL; CRM_CHECK(section != NULL, return cib_missing); CRM_CHECK(attr_name != NULL || attr_id != NULL, return cib_missing); if(safe_str_eq(section, XML_CIB_TAG_NODES)) { CRM_CHECK(node_uuid != NULL, return cib_NOTEXISTS); } else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) { CRM_CHECK(node_uuid != NULL, return cib_NOTEXISTS); } rc = the_cib->cmds->query(the_cib, section, &xml_search, cib_sync_call|cib_scope_local); if(rc != cib_ok) { crm_err("Query failed for attribute %s (section=%s, node=%s, set=%s): %s", attr_name, section, crm_str(set_name), crm_str(node_uuid), cib_error2string(rc)); return rc; } xml_obj = find_attr_details( xml_search, node_uuid, set_name, attr_id, attr_name); free_xml(xml_search); if(xml_obj != NULL) { local_attr_id = crm_strdup(ID(xml_obj)); attr_id = local_attr_id; } if(attr_id == NULL || xml_obj == NULL) { attr_common_setup(section); CRM_CHECK(attr_id != NULL, return cib_missing); CRM_CHECK(set_name != NULL, return cib_missing); if(attr_value == NULL) { return cib_missing_data; } if(is_node_transient) { xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_STATE); crm_xml_add(xml_obj, XML_ATTR_ID, node_uuid); if(xml_top == NULL) { xml_top = xml_obj; } } crm_debug_2("Creating %s/%s", section, tag); if(tag != NULL) { xml_obj = create_xml_node(xml_obj, tag); crm_xml_add(xml_obj, XML_ATTR_ID, node_uuid); if(xml_top == NULL) { xml_top = xml_obj; } } if(node_uuid == NULL) { xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_PROPSET); } else { xml_obj = create_xml_node(xml_obj, XML_TAG_ATTR_SETS); } crm_xml_add(xml_obj, XML_ATTR_ID, set_name); if(xml_top == NULL) { xml_top = xml_obj; } xml_obj = create_xml_node(xml_obj, XML_TAG_ATTRS); crm_free(local_set_name); } else { xml_obj = NULL; } xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR); if(xml_top == NULL) { xml_top = xml_obj; } crm_xml_add(xml_obj, XML_ATTR_ID, attr_id); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value); crm_log_xml_debug_2(xml_top, "update_attr"); rc = the_cib->cmds->modify(the_cib, section, xml_top, NULL, call_options|cib_quorum_override); if(rc == cib_diff_resync) { /* this is an internal matter - the update succeeded */ rc = cib_ok; } if(rc < cib_ok) { crm_err("Error setting %s=%s (section=%s, set=%s): %s", attr_name, attr_value, section, crm_str(set_name), cib_error2string(rc)); crm_log_xml_info(xml_top, "Update"); } crm_free(local_attr_id); free_xml(xml_top); return rc; } enum cib_errors read_attr(cib_t *the_cib, const char *section, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, char **attr_value) { enum cib_errors rc = cib_ok; crm_data_t *xml_obj = NULL; crm_data_t *xml_next = NULL; crm_data_t *fragment = NULL; CRM_CHECK(section != NULL, return cib_missing); CRM_CHECK(attr_name != NULL || attr_id != NULL, return cib_missing); if(safe_str_eq(section, XML_CIB_TAG_NODES)) { CRM_CHECK(node_uuid != NULL, return cib_NOTEXISTS); } else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) { CRM_CHECK(node_uuid != NULL, return cib_NOTEXISTS); } CRM_ASSERT(attr_value != NULL); *attr_value = NULL; crm_debug("Searching for attribute %s (section=%s, node=%s, set=%s)", attr_name, section, crm_str(node_uuid), crm_str(set_name)); rc = the_cib->cmds->query( the_cib, section, &fragment, cib_sync_call); if(rc != cib_ok) { crm_err("Query failed for attribute %s (section=%s, node=%s, set=%s): %s", attr_name, section, crm_str(set_name), crm_str(node_uuid), cib_error2string(rc)); return rc; } #if CRM_DEPRECATED_SINCE_2_0_4 if(safe_str_eq(crm_element_name(fragment), section)) { xml_obj = fragment; } else { crm_data_t *a_node = NULL; a_node = find_xml_node(fragment, XML_TAG_CIB, TRUE); xml_obj = get_object_root(section, a_node); } #else xml_obj = fragment; CRM_CHECK(safe_str_eq(crm_element_name(xml_obj), section), return cib_output_data); #endif CRM_ASSERT(xml_obj != NULL); crm_log_xml_debug_2(xml_obj, "Result section"); xml_next = find_attr_details( xml_obj, node_uuid, set_name, attr_id, attr_name); if(xml_next != NULL) { *attr_value = crm_element_value_copy( xml_next, XML_NVPAIR_ATTR_VALUE); } free_xml(fragment); return xml_next == NULL?cib_NOTEXISTS:cib_ok; } enum cib_errors delete_attr(cib_t *the_cib, int options, const char *section, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, const char *attr_value) { enum cib_errors rc = cib_ok; crm_data_t *xml_obj = NULL; crm_data_t *xml_search = NULL; char *local_attr_id = NULL; CRM_CHECK(section != NULL, return cib_missing); CRM_CHECK(attr_name != NULL || attr_id != NULL, return cib_missing); if(safe_str_eq(section, XML_CIB_TAG_NODES)) { CRM_CHECK(node_uuid != NULL, return cib_NOTEXISTS); } else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) { CRM_CHECK(node_uuid != NULL, return cib_NOTEXISTS); } if(attr_id == NULL || attr_value != NULL) { rc = the_cib->cmds->query(the_cib, section, &xml_search, cib_sync_call|cib_scope_local); if(rc != cib_ok) { crm_err("Query failed for section=%s of the CIB: %s", section, cib_error2string(rc)); return rc; } xml_obj = find_attr_details( xml_search, node_uuid, set_name, attr_id, attr_name); free_xml(xml_search); if(xml_obj != NULL) { if(attr_value != NULL) { const char *current = crm_element_value(xml_obj, XML_NVPAIR_ATTR_VALUE); if(safe_str_neq(attr_value, current)) { return cib_NOTEXISTS; } } local_attr_id = crm_strdup(ID(xml_obj)); attr_id = local_attr_id; xml_obj = NULL; } } if(attr_id == NULL) { return cib_NOTEXISTS; } xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR); crm_xml_add(xml_obj, XML_ATTR_ID, attr_id); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value); rc = the_cib->cmds->delete( the_cib, section, xml_obj, NULL, options|cib_quorum_override); crm_free(local_attr_id); free_xml(xml_obj); return rc; } enum cib_errors query_node_uuid(cib_t *the_cib, const char *uname, char **uuid) { enum cib_errors rc = cib_ok; crm_data_t *xml_obj = NULL; crm_data_t *fragment = NULL; const char *child_name = NULL; CRM_ASSERT(uname != NULL); CRM_ASSERT(uuid != NULL); rc = the_cib->cmds->query(the_cib, XML_CIB_TAG_NODES, &fragment, cib_sync_call|cib_scope_local); if(rc != cib_ok) { return rc; } #if CRM_DEPRECATED_SINCE_2_0_4 if(safe_str_eq(crm_element_name(fragment), XML_CIB_TAG_NODES)) { xml_obj = fragment; } else { xml_obj = find_xml_node(fragment, XML_TAG_CIB, TRUE); xml_obj = get_object_root(XML_CIB_TAG_NODES, xml_obj); } #else xml_obj = fragment; CRM_CHECK(safe_str_eq(crm_element_name(xml_obj), XML_CIB_TAG_NODES), return cib_output_data); #endif CRM_ASSERT(xml_obj != NULL); crm_log_xml_debug(xml_obj, "Result section"); rc = cib_NOTEXISTS; *uuid = NULL; xml_child_iter_filter( xml_obj, a_child, XML_CIB_TAG_NODE, child_name = crm_element_value(a_child, XML_ATTR_UNAME); if(safe_str_eq(uname, child_name)) { child_name = ID(a_child); if(child_name != NULL) { *uuid = crm_strdup(child_name); rc = cib_ok; } break; } ); free_xml(fragment); return rc; } enum cib_errors query_node_uname(cib_t *the_cib, const char *uuid, char **uname) { enum cib_errors rc = cib_ok; crm_data_t *xml_obj = NULL; crm_data_t *fragment = NULL; const char *child_name = NULL; CRM_ASSERT(uname != NULL); CRM_ASSERT(uuid != NULL); rc = the_cib->cmds->query(the_cib, XML_CIB_TAG_NODES, &fragment, cib_sync_call|cib_scope_local); if(rc != cib_ok) { return rc; } #if CRM_DEPRECATED_SINCE_2_0_4 if(safe_str_eq(crm_element_name(fragment), XML_CIB_TAG_NODES)) { xml_obj = fragment; } else { xml_obj = find_xml_node(fragment, XML_TAG_CIB, TRUE); xml_obj = get_object_root(XML_CIB_TAG_NODES, xml_obj); } #else xml_obj = fragment; CRM_CHECK(safe_str_eq(crm_element_name(xml_obj), XML_CIB_TAG_NODES), return cib_output_data); #endif CRM_ASSERT(xml_obj != NULL); crm_log_xml_debug_2(xml_obj, "Result section"); rc = cib_NOTEXISTS; *uname = NULL; xml_child_iter_filter( xml_obj, a_child, XML_CIB_TAG_NODE, child_name = ID(a_child); if(safe_str_eq(uuid, child_name)) { child_name = crm_element_value(a_child, XML_ATTR_UNAME); if(child_name != NULL) { *uname = crm_strdup(child_name); rc = cib_ok; } break; } ); free_xml(fragment); return rc; } #define standby_common char *attr_id = NULL; \ int str_length = 3; \ char *set_name = NULL; \ const char *attr_name = "standby"; \ - const char *type = XML_CIB_TAG_NODES; \ \ CRM_CHECK(uuid != NULL, return cib_missing_data); \ str_length += strlen(attr_name); \ str_length += strlen(uuid); \ - if(safe_str_eq(scope, "reboot") \ - || safe_str_eq(scope, XML_CIB_TAG_STATUS)) { \ + if(safe_str_eq(type, "reboot") \ + || safe_str_eq(type, XML_CIB_TAG_STATUS)) { \ const char *extra = "transient"; \ type = XML_CIB_TAG_STATUS; \ str_length += strlen(extra); \ crm_malloc0(attr_id, str_length); \ sprintf(attr_id, "%s-%s-%s", extra, attr_name, uuid); \ \ } else { \ crm_malloc0(attr_id, str_length); \ sprintf(attr_id, "%s-%s", attr_name, uuid); \ } enum cib_errors -query_standby(cib_t *the_cib, const char *uuid, const char *scope, - char **standby_value) +query_standby(cib_t *the_cib, const char *uuid, + char **scope, char **standby_value) { enum cib_errors rc = cib_ok; CRM_CHECK(standby_value != NULL, return cib_missing_data); - - if(scope != NULL) { + CRM_CHECK(scope != NULL, return cib_missing_data); + + if(*scope != NULL) { + const char *type = *scope; standby_common; rc = read_attr(the_cib, type, uuid, set_name, attr_id, attr_name, standby_value); crm_free(attr_id); crm_free(set_name); } else { - rc = query_standby( - the_cib, uuid, XML_CIB_TAG_NODES, standby_value); + *scope = crm_strdup(XML_CIB_TAG_NODE); + rc = query_standby(the_cib, uuid, scope, standby_value); if(rc == cib_NOTEXISTS) { + crm_free(*scope); + *scope = crm_strdup(XML_CIB_TAG_STATUS); crm_debug("No standby value found with " "lifetime=forever, checking lifetime=reboot"); - rc = query_standby(the_cib, uuid, - XML_CIB_TAG_STATUS, standby_value); + rc = query_standby(the_cib, uuid, scope, standby_value); } } return rc; } enum cib_errors set_standby(cib_t *the_cib, const char *uuid, const char *scope, const char *standby_value) { enum cib_errors rc = cib_ok; CRM_CHECK(standby_value != NULL, return cib_missing_data); if(scope != NULL) { + const char *type = scope; standby_common; rc = update_attr(the_cib, cib_sync_call, type, uuid, set_name, attr_id, attr_name, standby_value); crm_free(attr_id); crm_free(set_name); } else { rc = set_standby(the_cib, uuid, XML_CIB_TAG_NODES, standby_value); } return rc; } enum cib_errors delete_standby(cib_t *the_cib, const char *uuid, const char *scope, const char *standby_value) { enum cib_errors rc = cib_ok; if(scope != NULL) { + const char *type = scope; standby_common; rc = delete_attr(the_cib, cib_sync_call, type, uuid, set_name, attr_id, attr_name, standby_value); crm_free(attr_id); crm_free(set_name); } else { rc = delete_standby( the_cib, uuid, XML_CIB_TAG_STATUS, standby_value); rc = delete_standby( the_cib, uuid, XML_CIB_TAG_NODES, standby_value); } return rc; }