diff --git a/include/crm/cib/internal.h b/include/crm/cib/internal.h index 2560fbebe6..336222e13c 100644 --- a/include/crm/cib/internal.h +++ b/include/crm/cib/internal.h @@ -1,244 +1,260 @@ /* * Copyright 2004-2022 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #ifndef CIB_INTERNAL__H # define CIB_INTERNAL__H # include # include # include # 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_MODIFY "cib_modify" # define CIB_OP_DELETE "cib_delete" # define CIB_OP_ERASE "cib_erase" # define CIB_OP_REPLACE "cib_replace" # define CIB_OP_APPLY_DIFF "cib_apply_diff" # define CIB_OP_UPGRADE "cib_upgrade" # define CIB_OP_DELETE_ALT "cib_delete_alt" # 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_UPGRADE_RC "cib_upgrade_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_async_id" # 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 F_CIB_USER "cib_user" # define F_CIB_LOCAL_NOTIFY_ID "cib_local_notify_id" # define F_CIB_PING_ID "cib_ping_id" # define F_CIB_SCHEMA_MAX "cib_schema_max" # define F_CIB_CHANGE_SECTION "cib_change_section" # 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_REPLACE_NOTIFY "cib_refresh_notify" enum cib_change_section_info { cib_change_section_none = 0x00000000, cib_change_section_nodes = 0x00000001, cib_change_section_alerts = 0x00000002, cib_change_section_status = 0x00000004 }; gboolean cib_diff_version_details(xmlNode * diff, int *admin_epoch, int *epoch, int *updates, int *_admin_epoch, int *_epoch, int *_updates); gboolean cib_read_config(GHashTable * options, xmlNode * current_cib); void verify_cib_options(GHashTable * options); gboolean cib_internal_config_changed(xmlNode * diff); 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, xmlNode * msg); } cib_notify_client_t; typedef struct cib_callback_client_s { void (*callback) (xmlNode *, int, int, xmlNode *, void *); const char *id; void *user_data; gboolean only_success; struct timer_rec_s *timer; void (*free_func)(void *); } cib_callback_client_t; struct timer_rec_s { int call_id; int timeout; guint ref; cib_t *cib; }; #define cib__set_call_options(cib_call_opts, call_for, flags_to_set) do { \ cib_call_opts = pcmk__set_flags_as(__func__, __LINE__, \ LOG_TRACE, "CIB call", (call_for), (cib_call_opts), \ (flags_to_set), #flags_to_set); \ } while (0) #define cib__clear_call_options(cib_call_opts, call_for, flags_to_clear) do { \ cib_call_opts = pcmk__clear_flags_as(__func__, __LINE__, \ LOG_TRACE, "CIB call", (call_for), (cib_call_opts), \ (flags_to_clear), #flags_to_clear); \ } while (0) typedef int (*cib_op_t) (const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **); cib_t *cib_new_variant(void); int cib_perform_op(const char *op, int call_options, cib_op_t * fn, gboolean is_query, const char *section, xmlNode * req, xmlNode * input, gboolean manage_counters, gboolean * config_changed, xmlNode * current_cib, xmlNode ** result_cib, xmlNode ** diff, xmlNode ** output); xmlNode *cib_create_op(int call_id, const char *token, const char *op, const char *host, const char *section, xmlNode * data, int call_options, const char *user_name); void cib_native_callback(cib_t * cib, xmlNode * msg, int call_id, int rc); void cib_native_notify(gpointer data, gpointer user_data); int cib_native_register_notification(cib_t * cib, const char *callback, int enabled); gboolean cib_client_register_callback(cib_t * cib, int call_id, int timeout, gboolean only_success, void *user_data, const char *callback_name, void (*callback) (xmlNode *, int, int, xmlNode *, void *)); gboolean cib_client_register_callback_full(cib_t *cib, int call_id, int timeout, gboolean only_success, void *user_data, const char *callback_name, void (*callback)(xmlNode *, int, int, xmlNode *, void *), void (*free_func)(void *)); int cib_process_query(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); int cib_process_erase(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); int cib_process_bump(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); int cib_process_replace(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); int cib_process_create(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); int cib_process_modify(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); int cib_process_delete(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); int cib_process_diff(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); int cib_process_upgrade(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); /*! * \internal * \brief Query or modify a CIB * * \param[in] op CIB_OP_* operation to be performed * \param[in] options Flag set of \c cib_call_options * \param[in] section XPath to query or modify * \param[in] req unused * \param[in] input Portion of CIB to modify (used with * CIB_OP_CREATE, CIB_OP_MODIFY, and * CIB_OP_REPLACE) * \param[in] existing_cib Input CIB (used with CIB_OP_QUERY) * \param[in,out] result_cib CIB copy to make changes in (used with * CIB_OP_CREATE, CIB_OP_MODIFY, CIB_OP_DELETE, and * CIB_OP_REPLACE) * \param[out] answer Query result (used with CIB_OP_QUERY) * * \return Legacy Pacemaker return code */ int cib_process_xpath(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); gboolean cib_config_changed(xmlNode * last, xmlNode * next, xmlNode ** diff); gboolean update_results(xmlNode * failed, xmlNode * target, const char *operation, int return_code); int cib_update_counter(xmlNode * xml_obj, const char *field, gboolean reset); int cib_internal_op(cib_t * cib, const char *op, const char *host, const char *section, xmlNode * data, xmlNode ** output_data, int call_options, const char *user_name); int cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root); int cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname, const char *cib_filename); void cib__set_output(cib_t *cib, pcmk__output_t *out); cib_callback_client_t* cib__lookup_id (int call_id); /*! * \internal * \brief Connect to, query, and optionally disconnect from the CIB, returning * the resulting XML object. * * \param[out] cib If non-NULL, a pointer to where to store the CIB * connection. In this case, it is up to the caller to * disconnect from the CIB when finished. * \param[out] cib_object A pointer to where to store the XML query result. * * \return A standard Pacemaker return code */ int cib__signon_query(cib_t **cib, xmlNode **cib_object); int cib__clean_up_connection(cib_t **cib); +int cib__update_node_attr(pcmk__output_t *out, cib_t *cib, int call_options, + const char *section, const char *node_uuid, const char *set_type, + const char *set_name, const char *attr_id, const char *attr_name, + const char *attr_value, const char *user_name, + const char *node_type); + +int cib__read_node_attr(pcmk__output_t *out, cib_t *cib, const char *section, + const char *node_uuid, const char *set_type, const char *set_name, + const char *attr_id, const char *attr_name, char **attr_value, + const char *user_name); + +int cib__delete_node_attr(pcmk__output_t *out, cib_t *cib, int options, + const char *section, const char *node_uuid, const char *set_type, + const char *set_name, const char *attr_id, const char *attr_name, + const char *attr_value, const char *user_name); + #endif diff --git a/lib/cib/cib_attrs.c b/lib/cib/cib_attrs.c index de7d9cc7b3..01956b04df 100644 --- a/lib/cib/cib_attrs.c +++ b/lib/cib/cib_attrs.c @@ -1,594 +1,701 @@ /* * Copyright 2004-2022 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include -#define attr_msg(level, fmt, args...) do { \ - if(to_console) { \ - printf(fmt"\n", ##args); \ - } else { \ - do_crm_log(level, fmt , ##args); \ - } \ - } while(0) - /* could also check for possible truncation */ #define attr_snprintf(_str, _offset, _limit, ...) do { \ _offset += snprintf(_str + _offset, \ (_limit > _offset) ? _limit - _offset : 0, \ __VA_ARGS__); \ } while(0) #define XPATH_MAX 1024 -extern int -find_nvpair_attr_delegate(cib_t * the_cib, const char *attr, const char *section, - const char *node_uuid, const char *attr_set_type, const char *set_name, - const char *attr_id, const char *attr_name, gboolean to_console, - char **value, const char *user_name) +static pcmk__output_t * +new_output_object(const char *ty) +{ + int rc = pcmk_rc_ok; + pcmk__output_t *out = NULL; + const char* argv[] = { "", NULL }; + pcmk__supported_format_t formats[] = { + PCMK__SUPPORTED_FORMAT_LOG, + PCMK__SUPPORTED_FORMAT_TEXT, + { NULL, NULL, NULL } + }; + + pcmk__register_formats(NULL, formats); + rc = pcmk__output_new(&out, ty, NULL, (char**)argv); + if ((rc != pcmk_rc_ok) || (out == NULL)) { + crm_err("Can't out due to internal error: %s", pcmk_rc_str(rc)); + return NULL; + } + + return out; +} + +static int +find_attr(pcmk__output_t *out, cib_t *cib, const char *attr, const char *section, + const char *node_uuid, const char *attr_set_type, const char *set_name, + const char *attr_id, const char *attr_name, char **value, + const char *user_name) { int offset = 0; - int rc = pcmk_ok; + int rc = pcmk_rc_ok; const char *xpath_base = NULL; char *xpath_string = NULL; xmlNode *xml_search = NULL; const char *set_type = NULL; const char *node_type = NULL; if (attr_set_type) { set_type = attr_set_type; } else { set_type = XML_TAG_ATTR_SETS; } CRM_ASSERT(value != NULL); *value = NULL; if (pcmk__str_eq(section, XML_CIB_TAG_CRMCONFIG, pcmk__str_casei)) { node_uuid = NULL; set_type = XML_CIB_TAG_PROPSET; } else if (pcmk__strcase_any_of(section, XML_CIB_TAG_OPCONFIG, XML_CIB_TAG_RSCCONFIG, NULL)) { node_uuid = NULL; set_type = XML_TAG_META_SETS; } else if (pcmk__str_eq(section, XML_CIB_TAG_TICKETS, pcmk__str_casei)) { node_uuid = NULL; section = XML_CIB_TAG_STATUS; node_type = XML_CIB_TAG_TICKETS; } else if (node_uuid == NULL) { - return -EINVAL; + return EINVAL; } xpath_base = pcmk_cib_xpath_for(section); if (xpath_base == NULL) { crm_warn("%s CIB section not known", section); - return -ENOMSG; + return ENOMSG; } xpath_string = calloc(1, XPATH_MAX); if (xpath_string == NULL) { crm_perror(LOG_CRIT, "Could not create xpath"); - return -ENOMEM; + return ENOMEM; } attr_snprintf(xpath_string, offset, XPATH_MAX, "%s", xpath_base); if (pcmk__str_eq(node_type, XML_CIB_TAG_TICKETS, pcmk__str_casei)) { attr_snprintf(xpath_string, offset, XPATH_MAX, "//%s", node_type); } else if (node_uuid) { const char *node_type = XML_CIB_TAG_NODE; if (pcmk__str_eq(section, XML_CIB_TAG_STATUS, pcmk__str_casei)) { node_type = XML_CIB_TAG_STATE; set_type = XML_TAG_TRANSIENT_NODEATTRS; } attr_snprintf(xpath_string, offset, XPATH_MAX, "//%s[@id='%s']", node_type, node_uuid); } if (set_name) { attr_snprintf(xpath_string, offset, XPATH_MAX, "//%s[@id='%.128s']", set_type, set_name); } else { attr_snprintf(xpath_string, offset, XPATH_MAX, "//%s", set_type); } attr_snprintf(xpath_string, offset, XPATH_MAX, "//nvpair["); if (attr_id) { attr_snprintf(xpath_string, offset, XPATH_MAX, "@id='%s'", attr_id); } if (attr_name) { if (attr_id) { attr_snprintf(xpath_string, offset, XPATH_MAX, " and "); } attr_snprintf(xpath_string, offset, XPATH_MAX, "@name='%.128s'", attr_name); } attr_snprintf(xpath_string, offset, XPATH_MAX, "]"); CRM_LOG_ASSERT(offset > 0); - rc = cib_internal_op(the_cib, CIB_OP_QUERY, NULL, xpath_string, NULL, &xml_search, + rc = cib_internal_op(cib, CIB_OP_QUERY, NULL, xpath_string, NULL, &xml_search, cib_sync_call | cib_scope_local | cib_xpath, user_name); + rc = pcmk_legacy2rc(rc); - if (rc != pcmk_ok) { + if (rc != pcmk_rc_ok) { crm_trace("Query failed for attribute %s (section=%s, node=%s, set=%s, xpath=%s): %s", attr_name, section, crm_str(node_uuid), crm_str(set_name), xpath_string, - pcmk_strerror(rc)); + pcmk_rc_str(rc)); goto done; } crm_log_xml_debug(xml_search, "Match"); if (xml_has_children(xml_search)) { xmlNode *child = NULL; - rc = -ENOTUNIQ; - attr_msg(LOG_WARNING, "Multiple attributes match name=%s", attr_name); + rc = ENOTUNIQ; + out->info(out, "Multiple attributes match name=%s", attr_name); for (child = pcmk__xml_first_child(xml_search); child != NULL; child = pcmk__xml_next(child)) { - attr_msg(LOG_INFO, " Value: %s \t(id=%s)", - crm_element_value(child, XML_NVPAIR_ATTR_VALUE), ID(child)); + out->info(out, " Value: %s \t(id=%s)", + crm_element_value(child, XML_NVPAIR_ATTR_VALUE), ID(child)); } } else { pcmk__str_update(value, crm_element_value(xml_search, attr)); } done: free(xpath_string); free_xml(xml_search); return rc; } int -update_attr_delegate(cib_t * the_cib, int call_options, - const char *section, const char *node_uuid, const char *set_type, - const char *set_name, const char *attr_id, const char *attr_name, - const char *attr_value, gboolean to_console, const char *user_name, - const char *node_type) +cib__update_node_attr(pcmk__output_t *out, cib_t *cib, int call_options, const char *section, + const char *node_uuid, const char *set_type, const char *set_name, + const char *attr_id, const char *attr_name, const char *attr_value, + const char *user_name, const char *node_type) { const char *tag = NULL; - int rc = pcmk_ok; + int rc = pcmk_rc_ok; xmlNode *xml_top = NULL; xmlNode *xml_obj = NULL; char *local_attr_id = NULL; char *local_set_name = NULL; - CRM_CHECK(section != NULL, return -EINVAL); - CRM_CHECK(attr_value != NULL, return -EINVAL); - CRM_CHECK(attr_name != NULL || attr_id != NULL, return -EINVAL); + CRM_CHECK(section != NULL, return EINVAL); + CRM_CHECK(attr_value != NULL, return EINVAL); + CRM_CHECK(attr_name != NULL || attr_id != NULL, return EINVAL); - rc = find_nvpair_attr_delegate(the_cib, XML_ATTR_ID, section, node_uuid, set_type, set_name, - attr_id, attr_name, to_console, &local_attr_id, user_name); - if (rc == pcmk_ok) { + rc = find_attr(out, cib, XML_ATTR_ID, section, node_uuid, set_type, set_name, + attr_id, attr_name, &local_attr_id, user_name); + if (rc == pcmk_rc_ok) { attr_id = local_attr_id; goto do_modify; - } else if (rc != -ENXIO) { + } else if (rc != ENXIO) { return rc; /* } else if(attr_id == NULL) { */ - /* return -EINVAL; */ + /* return EINVAL; */ } else { crm_trace("%s does not exist, create it", attr_name); if (pcmk__str_eq(section, XML_CIB_TAG_TICKETS, pcmk__str_casei)) { node_uuid = NULL; section = XML_CIB_TAG_STATUS; node_type = XML_CIB_TAG_TICKETS; xml_top = create_xml_node(xml_obj, XML_CIB_TAG_STATUS); xml_obj = create_xml_node(xml_top, XML_CIB_TAG_TICKETS); } else if (pcmk__str_eq(section, XML_CIB_TAG_NODES, pcmk__str_casei)) { if (node_uuid == NULL) { - return -EINVAL; + return EINVAL; } if (pcmk__str_eq(node_type, "remote", pcmk__str_casei)) { xml_top = create_xml_node(xml_obj, XML_CIB_TAG_NODES); xml_obj = create_xml_node(xml_top, XML_CIB_TAG_NODE); crm_xml_add(xml_obj, XML_ATTR_TYPE, "remote"); crm_xml_add(xml_obj, XML_ATTR_ID, node_uuid); crm_xml_add(xml_obj, XML_ATTR_UNAME, node_uuid); } else { tag = XML_CIB_TAG_NODE; } } else if (pcmk__str_eq(section, XML_CIB_TAG_STATUS, pcmk__str_casei)) { tag = XML_TAG_TRANSIENT_NODEATTRS; if (node_uuid == NULL) { - return -EINVAL; + return EINVAL; } xml_top = create_xml_node(xml_obj, XML_CIB_TAG_STATE); crm_xml_add(xml_top, XML_ATTR_ID, node_uuid); xml_obj = xml_top; } else { tag = section; node_uuid = NULL; } if (set_name == NULL) { if (pcmk__str_eq(section, XML_CIB_TAG_CRMCONFIG, pcmk__str_casei)) { local_set_name = strdup(CIB_OPTIONS_FIRST); } else if (pcmk__str_eq(node_type, XML_CIB_TAG_TICKETS, pcmk__str_casei)) { local_set_name = crm_strdup_printf("%s-%s", section, XML_CIB_TAG_TICKETS); } else if (node_uuid) { local_set_name = crm_strdup_printf("%s-%s", section, node_uuid); if (set_type) { char *tmp_set_name = local_set_name; local_set_name = crm_strdup_printf("%s-%s", tmp_set_name, set_type); free(tmp_set_name); } } else { local_set_name = crm_strdup_printf("%s-options", section); } set_name = local_set_name; } if (attr_id == NULL) { local_attr_id = crm_strdup_printf("%s-%s", set_name, attr_name); crm_xml_sanitize_id(local_attr_id); attr_id = local_attr_id; } else if (attr_name == NULL) { attr_name = attr_id; } crm_trace("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 && !pcmk__str_eq(node_type, XML_CIB_TAG_TICKETS, pcmk__str_casei)) { if (pcmk__str_eq(section, XML_CIB_TAG_CRMCONFIG, pcmk__str_casei)) { xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_PROPSET); } else { xml_obj = create_xml_node(xml_obj, XML_TAG_META_SETS); } } else if (set_type) { xml_obj = create_xml_node(xml_obj, set_type); } 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; } } do_modify: xml_obj = crm_create_nvpair_xml(xml_obj, attr_id, attr_name, attr_value); if (xml_top == NULL) { xml_top = xml_obj; } crm_log_xml_trace(xml_top, "update_attr"); - rc = cib_internal_op(the_cib, CIB_OP_MODIFY, NULL, section, xml_top, NULL, + rc = cib_internal_op(cib, CIB_OP_MODIFY, NULL, section, xml_top, NULL, call_options | cib_quorum_override, user_name); + rc = pcmk_legacy2rc(rc); - if (rc < pcmk_ok) { - attr_msg(LOG_ERR, "Error setting %s=%s (section=%s, set=%s): %s", - attr_name, attr_value, section, crm_str(set_name), pcmk_strerror(rc)); + if (rc != pcmk_rc_ok) { + out->err(out, "Error setting %s=%s (section=%s, set=%s): %s", + attr_name, attr_value, section, crm_str(set_name), pcmk_rc_str(rc)); crm_log_xml_info(xml_top, "Update"); } free(local_set_name); free(local_attr_id); free_xml(xml_top); return rc; } int -read_attr_delegate(cib_t * the_cib, - const char *section, const char *node_uuid, const char *set_type, - const char *set_name, const char *attr_id, const char *attr_name, - char **attr_value, gboolean to_console, const char *user_name) +cib__read_node_attr(pcmk__output_t *out, cib_t *cib, const char *section, + const char *node_uuid, const char *set_type, const char *set_name, + const char *attr_id, const char *attr_name, char **attr_value, + const char *user_name) { - int rc = pcmk_ok; + int rc = pcmk_rc_ok; CRM_ASSERT(attr_value != NULL); - CRM_CHECK(section != NULL, return -EINVAL); - CRM_CHECK(attr_name != NULL || attr_id != NULL, return -EINVAL); + CRM_CHECK(section != NULL, return EINVAL); + CRM_CHECK(attr_name != NULL || attr_id != NULL, return EINVAL); *attr_value = NULL; - rc = find_nvpair_attr_delegate(the_cib, XML_NVPAIR_ATTR_VALUE, section, node_uuid, set_type, - set_name, attr_id, attr_name, to_console, attr_value, user_name); - if (rc != pcmk_ok) { + rc = find_attr(out, cib, XML_NVPAIR_ATTR_VALUE, section, node_uuid, set_type, + set_name, attr_id, attr_name, attr_value, user_name); + if (rc != pcmk_rc_ok) { crm_trace("Query failed for attribute %s (section=%s, node=%s, set=%s): %s", attr_name, section, crm_str(set_name), crm_str(node_uuid), pcmk_strerror(rc)); } + return rc; } int -delete_attr_delegate(cib_t * the_cib, int options, - const char *section, const char *node_uuid, const char *set_type, - const char *set_name, const char *attr_id, const char *attr_name, - const char *attr_value, gboolean to_console, const char *user_name) +cib__delete_node_attr(pcmk__output_t *out, cib_t *cib, int options, const char *section, + const char *node_uuid, const char *set_type, const char *set_name, + const char *attr_id, const char *attr_name, const char *attr_value, + const char *user_name) { - int rc = pcmk_ok; + int rc = pcmk_rc_ok; xmlNode *xml_obj = NULL; char *local_attr_id = NULL; - CRM_CHECK(section != NULL, return -EINVAL); - CRM_CHECK(attr_name != NULL || attr_id != NULL, return -EINVAL); + CRM_CHECK(section != NULL, return EINVAL); + CRM_CHECK(attr_name != NULL || attr_id != NULL, return EINVAL); if (attr_id == NULL) { - rc = find_nvpair_attr_delegate(the_cib, XML_ATTR_ID, section, node_uuid, set_type, - set_name, attr_id, attr_name, to_console, &local_attr_id, - user_name); - if (rc != pcmk_ok) { + rc = find_attr(out, cib, XML_ATTR_ID, section, node_uuid, set_type, + set_name, attr_id, attr_name, &local_attr_id, + user_name); + if (rc != pcmk_rc_ok) { return rc; } attr_id = local_attr_id; } xml_obj = crm_create_nvpair_xml(NULL, attr_id, attr_name, attr_value); - rc = cib_internal_op(the_cib, CIB_OP_DELETE, NULL, section, xml_obj, NULL, + rc = cib_internal_op(cib, CIB_OP_DELETE, NULL, section, xml_obj, NULL, options | cib_quorum_override, user_name); + rc = pcmk_legacy2rc(rc); - if (rc == pcmk_ok) { - attr_msg(LOG_DEBUG, "Deleted %s %s: id=%s%s%s%s%s\n", - section, node_uuid ? "attribute" : "option", local_attr_id, - set_name ? " set=" : "", set_name ? set_name : "", - attr_name ? " name=" : "", attr_name ? attr_name : ""); + if (rc == pcmk_rc_ok) { + out->info(out, "Deleted %s %s: id=%s%s%s%s%s", + section, node_uuid ? "attribute" : "option", local_attr_id, + set_name ? " set=" : "", set_name ? set_name : "", + attr_name ? " name=" : "", attr_name ? attr_name : ""); } free(local_attr_id); free_xml(xml_obj); return rc; } +int +find_nvpair_attr_delegate(cib_t *cib, const char *attr, const char *section, + const char *node_uuid, const char *attr_set_type, const char *set_name, + const char *attr_id, const char *attr_name, gboolean to_console, + char **value, const char *user_name) +{ + pcmk__output_t *out = NULL; + int rc = pcmk_ok; + + out = new_output_object(to_console ? "text" : "log"); + if (out == NULL) { + return pcmk_err_generic; + } + + rc = find_attr(out, cib, attr, section, node_uuid, attr_set_type, + set_name, attr_id, attr_name, value, user_name); + + out->finish(out, CRM_EX_OK, true, NULL); + pcmk__output_free(out); + return pcmk_rc2legacy(rc); +} + +int +update_attr_delegate(cib_t *cib, int call_options, const char *section, + const char *node_uuid, const char *set_type, const char *set_name, + const char *attr_id, const char *attr_name, const char *attr_value, + gboolean to_console, const char *user_name, const char *node_type) +{ + pcmk__output_t *out = NULL; + int rc = pcmk_ok; + + out = new_output_object(to_console ? "text" : "log"); + if (out == NULL) { + return pcmk_err_generic; + } + + rc = cib__update_node_attr(out, cib, call_options, section, node_uuid, set_type, + set_name, attr_id, attr_name, attr_value, user_name, + node_type); + + out->finish(out, CRM_EX_OK, true, NULL); + pcmk__output_free(out); + return pcmk_rc2legacy(rc); +} + +int +read_attr_delegate(cib_t *cib, const char *section, const char *node_uuid, + const char *set_type, const char *set_name, const char *attr_id, + const char *attr_name, char **attr_value, gboolean to_console, + const char *user_name) +{ + pcmk__output_t *out = NULL; + int rc = pcmk_ok; + + out = new_output_object(to_console ? "text" : "log"); + if (out == NULL) { + return pcmk_err_generic; + } + + rc = cib__read_node_attr(out, cib, section, node_uuid, set_type, set_name, + attr_id, attr_name, attr_value, user_name); + + out->finish(out, CRM_EX_OK, true, NULL); + pcmk__output_free(out); + return pcmk_rc2legacy(rc); +} + +int +delete_attr_delegate(cib_t *cib, int options, const char *section, const char *node_uuid, + const char *set_type, const char *set_name, const char *attr_id, + const char *attr_name, const char *attr_value, gboolean to_console, + const char *user_name) +{ + pcmk__output_t *out = NULL; + int rc = pcmk_ok; + + out = new_output_object(to_console ? "text" : "log"); + if (out == NULL) { + return pcmk_err_generic; + } + + rc = cib__delete_node_attr(out, cib, options, section, node_uuid, set_type, + set_name, attr_id, attr_name, attr_value, user_name); + + out->finish(out, CRM_EX_OK, true, NULL); + pcmk__output_free(out); + return pcmk_rc2legacy(rc); +} + /*! * \internal * \brief Parse node UUID from search result * * \param[in] result XML search result * \param[out] uuid If non-NULL, where to store parsed UUID * \param[out] is_remote If non-NULL, set TRUE if result is remote node * * \return pcmk_ok if UUID was successfully parsed, -ENXIO otherwise */ static int get_uuid_from_result(xmlNode *result, char **uuid, int *is_remote) { int rc = -ENXIO; const char *tag; const char *parsed_uuid = NULL; int parsed_is_remote = FALSE; if (result == NULL) { return rc; } /* If there are multiple results, the first is sufficient */ tag = (const char *) (result->name); if (pcmk__str_eq(tag, "xpath-query", pcmk__str_casei)) { result = pcmk__xml_first_child(result); CRM_CHECK(result != NULL, return rc); tag = (const char *) (result->name); } if (pcmk__str_eq(tag, XML_CIB_TAG_NODE, pcmk__str_casei)) { /* Result is tag from section */ if (pcmk__str_eq(crm_element_value(result, XML_ATTR_TYPE), "remote", pcmk__str_casei)) { parsed_uuid = crm_element_value(result, XML_ATTR_UNAME); parsed_is_remote = TRUE; } else { parsed_uuid = ID(result); parsed_is_remote = FALSE; } } else if (pcmk__str_eq(tag, XML_CIB_TAG_RESOURCE, pcmk__str_casei)) { /* Result is for ocf:pacemaker:remote resource */ parsed_uuid = ID(result); parsed_is_remote = TRUE; } else if (pcmk__str_eq(tag, XML_CIB_TAG_NVPAIR, pcmk__str_casei)) { /* Result is remote-node parameter of for guest node */ parsed_uuid = crm_element_value(result, XML_NVPAIR_ATTR_VALUE); parsed_is_remote = TRUE; } else if (pcmk__str_eq(tag, XML_CIB_TAG_STATE, pcmk__str_casei)) { /* Result is tag from section */ parsed_uuid = crm_element_value(result, XML_ATTR_UNAME); if (pcmk__xe_attr_is_true(result, XML_NODE_IS_REMOTE)) { parsed_is_remote = TRUE; } } if (parsed_uuid) { if (uuid) { *uuid = strdup(parsed_uuid); } if (is_remote) { *is_remote = parsed_is_remote; } rc = pcmk_ok; } return rc; } /* Search string to find a node by name, as: * - cluster or remote node in nodes section * - remote node in resources section * - guest node in resources section * - orphaned remote node or bundle guest node in status section */ #define XPATH_UPPER_TRANS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" #define XPATH_LOWER_TRANS "abcdefghijklmnopqrstuvwxyz" #define XPATH_NODE \ "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_NODES \ "/" XML_CIB_TAG_NODE "[translate(@" XML_ATTR_UNAME ",'" XPATH_UPPER_TRANS "','" XPATH_LOWER_TRANS "') ='%s']" \ "|/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_RESOURCES \ "/" XML_CIB_TAG_RESOURCE \ "[@class='ocf'][@provider='pacemaker'][@type='remote'][translate(@id,'" XPATH_UPPER_TRANS "','" XPATH_LOWER_TRANS "') ='%s']" \ "|/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_RESOURCES \ "/" XML_CIB_TAG_RESOURCE "/" XML_TAG_META_SETS "/" XML_CIB_TAG_NVPAIR \ "[@name='" XML_RSC_ATTR_REMOTE_NODE "'][translate(@value,'" XPATH_UPPER_TRANS "','" XPATH_LOWER_TRANS "') ='%s']" \ "|/" XML_TAG_CIB "/" XML_CIB_TAG_STATUS "/" XML_CIB_TAG_STATE \ "[@" XML_NODE_IS_REMOTE "='true'][translate(@" XML_ATTR_UUID ",'" XPATH_UPPER_TRANS "','" XPATH_LOWER_TRANS "') ='%s']" int query_node_uuid(cib_t * the_cib, const char *uname, char **uuid, int *is_remote_node) { int rc = pcmk_ok; char *xpath_string; xmlNode *xml_search = NULL; char *host_lowercase = g_ascii_strdown(uname, -1); CRM_ASSERT(uname != NULL); if (uuid) { *uuid = NULL; } if (is_remote_node) { *is_remote_node = FALSE; } xpath_string = crm_strdup_printf(XPATH_NODE, host_lowercase, host_lowercase, host_lowercase, host_lowercase); if (cib_internal_op(the_cib, CIB_OP_QUERY, NULL, xpath_string, NULL, &xml_search, cib_sync_call|cib_scope_local|cib_xpath, NULL) == pcmk_ok) { rc = get_uuid_from_result(xml_search, uuid, is_remote_node); } else { rc = -ENXIO; } free(xpath_string); free_xml(xml_search); g_free(host_lowercase); if (rc != pcmk_ok) { crm_debug("Could not map node name '%s' to a UUID: %s", uname, pcmk_strerror(rc)); } else { crm_info("Mapped node name '%s' to UUID %s", uname, (uuid? *uuid : "")); } return rc; } int query_node_uname(cib_t * the_cib, const char *uuid, char **uname) { int rc = pcmk_ok; xmlNode *a_child = NULL; xmlNode *xml_obj = NULL; xmlNode *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 != pcmk_ok) { return rc; } xml_obj = fragment; CRM_CHECK(pcmk__str_eq(crm_element_name(xml_obj), XML_CIB_TAG_NODES, pcmk__str_casei), return -ENOMSG); CRM_ASSERT(xml_obj != NULL); crm_log_xml_trace(xml_obj, "Result section"); rc = -ENXIO; *uname = NULL; for (a_child = pcmk__xml_first_child(xml_obj); a_child != NULL; a_child = pcmk__xml_next(a_child)) { if (pcmk__str_eq((const char *)a_child->name, XML_CIB_TAG_NODE, pcmk__str_none)) { child_name = ID(a_child); if (pcmk__str_eq(uuid, child_name, pcmk__str_casei)) { child_name = crm_element_value(a_child, XML_ATTR_UNAME); if (child_name != NULL) { *uname = strdup(child_name); rc = pcmk_ok; } break; } } } free_xml(fragment); return rc; } int set_standby(cib_t * the_cib, const char *uuid, const char *scope, const char *standby_value) { int rc = pcmk_ok; char *attr_id = NULL; CRM_CHECK(uuid != NULL, return -EINVAL); CRM_CHECK(standby_value != NULL, return -EINVAL); if (pcmk__strcase_any_of(scope, "reboot", XML_CIB_TAG_STATUS, NULL)) { scope = XML_CIB_TAG_STATUS; attr_id = crm_strdup_printf("transient-standby-%.256s", uuid); } else { scope = XML_CIB_TAG_NODES; attr_id = crm_strdup_printf("standby-%.256s", uuid); } rc = update_attr_delegate(the_cib, cib_sync_call, scope, uuid, NULL, NULL, attr_id, "standby", standby_value, TRUE, NULL, NULL); free(attr_id); return rc; }