Logo Search packages:      
Sourcecode: pacemaker version File versions  Download package

cib_attrs.c

/* 
 * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
 * 
 * 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 <crm_internal.h>

#include <sys/param.h>

#include <crm/crm.h>

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>

#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/cib.h>


#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)) {    \
            node_uuid = NULL;                         \
            is_crm_config = TRUE;                           \
            tag = XML_CIB_TAG_CRMCONFIG;                    \
            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;                            \
      }                                               \

#define attr_msg(level, fmt, args...) do {      \
      if(to_console) {              \
          printf(fmt"\n", ##args);        \
      } else {                      \
          do_crm_log(level, fmt , ##args);      \
      }                             \
} while(0)

enum cib_errors
find_attr_details(crm_data_t *xml_search, const char *node_uuid,
              const char *set_name, const char *attr_id, const char *attr_name,
              crm_data_t **xml_obj, gboolean to_console)
{
      int matches = 0;
      crm_data_t *nv_children = NULL;
      crm_data_t *set_children = NULL;
      const char *set_type = XML_TAG_ATTR_SETS;
      const char *tag = crm_element_name(xml_search);

      CRM_CHECK(xml_obj != NULL, return cib_output_ptr);
      *xml_obj = NULL;
      
      CRM_CHECK(xml_search != NULL, return cib_NOTEXISTS);
      
      if(node_uuid != NULL || safe_str_eq(tag, XML_CIB_TAG_CRMCONFIG)) {
            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_2(set_children, "search by node:");
            if(matches == 0) {
                  CRM_CHECK(set_children == NULL, crm_err("Memory leak"));
                  attr_msg(LOG_INFO, "No node matching id=%s in %s",
                         node_uuid, TYPE(xml_search));
                  return cib_NOTEXISTS;
            }
      }

      crm_debug_2("Looking for (type=%s, set=%s, id=%s, name=%s) in %s",
                set_type, set_name, attr_id, attr_name, tag);

      /* filter by set name */
      if(set_name != NULL) {
            crm_data_t *tmp = NULL;
            matches = find_xml_children(
                  &tmp, set_children?set_children:xml_search, 
                  set_type, XML_ATTR_ID, set_name, FALSE);
            free_xml(set_children);
            set_children = tmp;
            crm_log_xml_debug_2(set_children, "search by set:");
            if(matches == 0) {
                  attr_msg(LOG_INFO, "No set matching id=%s in %s", set_name, TYPE(xml_search));
                  CRM_CHECK(set_children == NULL, crm_err("Memory leak"));
                  return cib_NOTEXISTS;
            }
      }

      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_2(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);
            free_xml(set_children);
            *xml_obj = single_match;
            return cib_ok;

      } else if(matches == 0) {
          free_xml(set_children);
          return cib_NOTEXISTS;
      }

      attr_msg(LOG_WARNING, "Multiple attributes match name=%s in %s:",
             attr_name, TYPE(xml_search));
      
      if(set_name != NULL) {
          xml_child_iter(
            nv_children, child,
            attr_msg(LOG_INFO, "  Value: %s \t(set=%s, id=%s)", 
                   crm_element_value(child, XML_NVPAIR_ATTR_VALUE), set_name, ID(child));
            );
          
      } else {
          free_xml(set_children);
          set_children = NULL;

          find_xml_children(
            &set_children, xml_search, 
            set_type, NULL, NULL, FALSE);

          xml_child_iter(
            set_children, set,
            const char *set_id = ID(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,
                attr_msg(LOG_INFO, "  Value: %s \t(set=%s, id=%s)",
                       crm_element_value(child, XML_NVPAIR_ATTR_VALUE),
                       set_id, ID(child));
                );
            );
      }
      
      free_xml(nv_children);
      free_xml(set_children);
      return cib_missing_data;
}


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, gboolean to_console)
{
      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_CRMCONFIG)) {
            node_uuid = NULL;

      } else 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) {
            attr_msg(LOG_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;
      }
            
      rc = find_attr_details(
          xml_search, node_uuid, set_name, attr_id, attr_name, &xml_obj, to_console);
      free_xml(xml_search);

      if(rc == cib_missing_data) {
          return rc;
      }
      
      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,
                    crm_free(local_attr_id);
                    free_xml(xml_obj);
                    return cib_missing);
            CRM_CHECK(set_name != NULL,
                    crm_free(local_attr_id);
                    free_xml(xml_obj);
                    return cib_missing);
            
            if(attr_value == NULL) {
                  crm_free(local_attr_id);
                  free_xml(xml_obj);
                  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 {
            free_xml(xml_obj);
            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) {
            attr_msg(LOG_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, gboolean to_console)
{
      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_CRMCONFIG)) {
            node_uuid = NULL;

      } else 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|cib_scope_local);

      if(rc != cib_ok) {
            attr_msg(LOG_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");
      
      rc = find_attr_details(
          xml_obj, node_uuid, set_name, attr_id, attr_name, &xml_next, to_console);
      free_xml(fragment);

      if(rc == cib_missing_data) {
          return rc;
      }
      
      if(xml_next != NULL) {
            *attr_value = crm_element_value_copy(
                  xml_next, XML_NVPAIR_ATTR_VALUE);
      }

      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, gboolean to_console)
{
      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_CRMCONFIG)) {
            node_uuid = NULL;

      } else 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) {
                  attr_msg(LOG_ERR, "Query failed for section=%s of the CIB: %s",
                        section, cib_error2string(rc));
                  return rc;
            }
            
            rc = find_attr_details(
                xml_search, node_uuid, set_name, attr_id, attr_name, &xml_obj, to_console);
            free_xml(xml_search);

            if(rc == cib_missing_data) {
                return rc;
            }
            
            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";                   \
                                                      \
      CRM_CHECK(uuid != NULL, return cib_missing_data);           \
      str_length += strlen(attr_name);                      \
      str_length += strlen(uuid);                           \
      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,
            char **scope, char **standby_value)
{
      enum cib_errors rc = cib_ok;
      CRM_CHECK(standby_value != NULL, return cib_missing_data);
      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, TRUE);
            crm_free(attr_id);
            crm_free(set_name);

      } else {
            *scope = crm_strdup(XML_CIB_TAG_NODES);
            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, 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, TRUE);
            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, TRUE);
            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;
}


Generated by  Doxygen 1.6.0   Back to index