Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/Makefile.am b/Makefile.am
index 9508c3aeca..9e337acb8f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,85 +1,81 @@
#
# linux-ha: Linux-HA code
#
# Copyright (C) 2002 Alan Robertson
#
# 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
# of the License, or (at your option) any later version.
#
# This program 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 program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
EXTRA_DIST = bootstrap ConfigureMe README.in libltdl.tar
RPM = @RPM@
RPMFLAGS = -ta
TARFILE = pacemaker.tar.gz
AM_TAR = tar
AUTOMAKE_OPTIONS = foreign
##ACLOCAL = aclocal -I $(auxdir)
MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure DRF/config-h.in \
DRF/stamp-h.in libtool.m4 ltdl.m4 libltdl.tar
## proc-ha is left out from SUBDIRS (completely obsolete)
if SNMP_SUBAGENT_BUILD
SNMP_SUBAGENT_DIR = snmp_subagent
endif
-if CIM_PROVIDER_BUILD
-CIM_PROVIDER_DIR = cim
-endif
-
SUBDIRS = debian build replace include lib cib crmd pengine transitioner crm tools doc cts
HANDY_DOCS = doc/ChangeLog doc/GettingStarted.html doc/DirectoryMap.txt
HBDOCS = doc/heartbeat_api.html
# Pass these to configure when running "make distcheck"
DISTCHECK_CONFIGURE_FLAGS = --with-initdir=prefix
tgz:
rm -f $(TARFILE)
hg archive -t tgz $(TARFILE)
echo Rebuilt $(TARFILE) on `date`
rpm: tgz
$(RPM) $(RPMFLAGS) $(TARFILE) </dev/null;
deb: tgz
rm -rf $(distdir)
tar -zxf $(TARFILE)
cd $(distdir) ; dpkg-buildpackage -rfakeroot -us -uc
rm -rf $(distdir)
install-exec-local:
dist-clean-local:
rm -f autoconf automake autoheader $(TARFILE)
maintainer-clean-local:
rm -f libltdl.tar
# "pkg" format for Solaris etc.
pkg:
(cd build/pkg && $(MAKE) PWD=`pwd` pkg)
# "port" format for BSD
portfile: dist
( cd build/port && $(MAKE) PWD=`pwd` portfile)
drpm: dist
$(RPM) --nodeps $(RPMFLAGS) $(TARFILE) </dev/null;
.PHONY: rpm pkg handy handy-copy
diff --git a/cib/Makefile.am b/cib/Makefile.am
index 0168d5f383..a7d753e6e0 100644
--- a/cib/Makefile.am
+++ b/cib/Makefile.am
@@ -1,66 +1,60 @@
#
# 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
# of the License, or (at your option) any later version.
#
# This program 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 program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
-I$(top_builddir)/libltdl -I$(top_srcdir)/libltdl \
-I$(AISPREFIX)/include/openais
EXTRA_DIST = cib.pam
hadir = $(sysconfdir)/ha.d
halibdir = $(libdir)/@HB_PKG@
commmoddir = $(halibdir)/modules/comm
-havarlibdir = $(localstatedir)/lib/@HB_PKG@
-
-# sockets with path
-crmdir = $(havarlibdir)/crm
-crmreqsocket = $(havarlibdir)/api/crm.req
-crmressocket = $(havarlibdir)/api/crm.rsp
COMMONLIBS = $(top_builddir)/lib/crm/common/libcrmcommon.la \
$(top_builddir)/lib/crm/cib/libcib.la \
$(GLIBLIB) \
$(LIBRT)
## binary progs
halib_PROGRAMS = cib cibmon
## SOURCES
#noinst_HEADERS = config.h control.h crmd.h
noinst_HEADERS = cibio.h cibmessages.h cibprimatives.h notify.h \
callbacks.h
cib_SOURCES = io.c primatives.c messages.c cib.c notify.c \
callbacks.c main.c remote.c
cib_LDADD = $(COMMONLIBS) $(CRYPTOLIB) $(CLUSTERLIBS) \
$(top_builddir)/lib/crm/common/libcrmcluster.la
cib_LDFLAGS = $(GNUTLSLIBS)
cibmon_SOURCES = cibmon.c
cibmon_LDADD = $(COMMONLIBS)
clean-generic:
rm -f *.log *.debug *.xml *~
install-exec-local:
# cp -f $(top_srcdir)/crm/cib/cib.pam $(DESTDIR)/etc/pam.d/cib
uninstall-local:
diff --git a/cib/io.c b/cib/io.c
index 33e65ebbad..f9f79e0184 100644
--- a/cib/io.c
+++ b/cib/io.c
@@ -1,836 +1,836 @@
/*
* 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 <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <heartbeat.h>
#include <crm/crm.h>
#include <cibio.h>
#include <crm/cib.h>
#include <crm/common/util.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/util.h>
#include <crm/common/cluster.h>
#include <clplumbing/cl_misc.h>
#include <clplumbing/lsb_exitcodes.h>
#include <cibprimatives.h>
int archive_file(const char *oldname, const char *newname, const char *ext, gboolean preserve);
const char * local_resource_path[] =
{
XML_CIB_TAG_STATUS,
};
const char * resource_path[] =
{
XML_CIB_TAG_RESOURCES,
};
const char * node_path[] =
{
XML_CIB_TAG_NODES,
};
const char * constraint_path[] =
{
XML_CIB_TAG_CONSTRAINTS,
};
gboolean initialized = FALSE;
crm_data_t *the_cib = NULL;
crm_data_t *node_search = NULL;
crm_data_t *resource_search = NULL;
crm_data_t *constraint_search = NULL;
crm_data_t *status_search = NULL;
extern gboolean cib_writes_enabled;
extern GTRIGSource *cib_writer;
extern enum cib_errors cib_status;
int set_connected_peers(crm_data_t *xml_obj);
void GHFunc_count_peers(gpointer key, gpointer value, gpointer user_data);
int write_cib_contents(gpointer p);
extern void cib_cleanup(void);
static gboolean
validate_cib_digest(crm_data_t *local_cib, const char *sigfile)
{
int s_res = -1;
struct stat buf;
char *digest = NULL;
char *expected = NULL;
gboolean passed = FALSE;
FILE *expected_strm = NULL;
int start = 0, length = 0, read_len = 0;
CRM_ASSERT(sigfile != NULL);
s_res = stat(sigfile, &buf);
if (s_res != 0) {
crm_warn("No on-disk digest present");
return TRUE;
}
if(local_cib != NULL) {
digest = calculate_xml_digest(local_cib, FALSE, FALSE);
}
expected_strm = fopen(sigfile, "r");
if(expected_strm == NULL) {
cl_perror("Could not open signature file %s for reading", sigfile);
goto bail;
}
start = ftell(expected_strm);
fseek(expected_strm, 0L, SEEK_END);
length = ftell(expected_strm);
fseek(expected_strm, 0L, start);
CRM_ASSERT(start == ftell(expected_strm));
crm_debug_3("Reading %d bytes from file", length);
crm_malloc0(expected, (length+1));
read_len = fread(expected, 1, length, expected_strm);
CRM_ASSERT(read_len == length);
fclose(expected_strm);
bail:
if(expected == NULL) {
crm_err("On-disk digest is empty");
} else if(safe_str_eq(expected, digest)) {
crm_debug_2("Digest comparision passed: %s", digest);
passed = TRUE;
} else {
crm_err("Digest comparision failed: expected %s (%s), calculated %s",
expected, sigfile, digest);
}
crm_free(digest);
crm_free(expected);
return passed;
}
static int
write_cib_digest(crm_data_t *local_cib, char *digest)
{
int rc = 0;
char *local_digest = NULL;
FILE *digest_strm = fopen(CIB_FILENAME ".sig", "w");
if(digest_strm == NULL) {
cl_perror("Cannot open signature file "CIB_FILENAME ".sig for writing");
return -1;
}
if(digest == NULL) {
local_digest = calculate_xml_digest(local_cib, FALSE, FALSE);
CRM_ASSERT(digest != NULL);
digest = local_digest;
}
rc = fprintf(digest_strm, "%s", digest);
if(rc < 0) {
cl_perror("Cannot write to signature file "CIB_FILENAME ".sig");
}
CRM_ASSERT(digest_strm != NULL);
if(fflush(digest_strm) != 0) {
cl_perror("fflush for %s failed:", digest);
rc = -1;
}
if(fsync(fileno(digest_strm)) < 0) {
cl_perror("fsync for %s failed:", digest);
rc = -1;
}
fclose(digest_strm);
crm_free(local_digest);
return rc;
}
static gboolean
validate_on_disk_cib(const char *filename, crm_data_t **on_disk_cib)
{
int s_res = -1;
struct stat buf;
FILE *cib_file = NULL;
gboolean passed = TRUE;
crm_data_t *root = NULL;
CRM_ASSERT(filename != NULL);
s_res = stat(filename, &buf);
if (s_res == 0) {
char *sigfile = NULL;
size_t fnsize;
cib_file = fopen(filename, "r");
if(cib_file == NULL) {
cl_perror("Couldn't open config file %s for reading", filename);
return FALSE;
}
crm_debug_2("Reading cluster configuration from: %s", filename);
root = file2xml(cib_file, FALSE);
fclose(cib_file);
fnsize = strlen(filename) + 5;
crm_malloc0(sigfile, fnsize);
snprintf(sigfile, fnsize, "%s.sig", filename);
if(validate_cib_digest(root, sigfile) == FALSE) {
passed = FALSE;
}
crm_free(sigfile);
}
if(on_disk_cib != NULL) {
*on_disk_cib = root;
} else {
free_xml(root);
}
return passed;
}
static int
cib_unlink(const char *file)
{
int rc = unlink(file);
if (rc < 0) {
cl_perror("Could not unlink %s - Disabling disk writes and continuing", file);
cib_writes_enabled = FALSE;
}
return rc;
}
/*
* It is the callers responsibility to free the output of this function
*/
static crm_data_t*
retrieveCib(const char *filename, const char *sigfile, gboolean archive_invalid)
{
struct stat buf;
FILE *cib_file = NULL;
crm_data_t *root = NULL;
crm_info("Reading cluster configuration from: %s (digest: %s)",
filename, sigfile);
if(stat(filename, &buf) != 0) {
crm_warn("Cluster configuration not found: %s", filename);
return NULL;
}
cib_file = fopen(filename, "r");
if(cib_file == NULL) {
cl_perror("Could not open config file %s for reading", filename);
} else {
root = file2xml(cib_file, FALSE);
fclose(cib_file);
}
if(root == NULL) {
crm_err("%s exists but does NOT contain valid XML. ", filename);
crm_warn("Continuing but %s will NOT used.", filename);
} else if(validate_cib_digest(root, sigfile) == FALSE) {
crm_err("Checksum of %s failed! Configuration contents ignored!", filename);
crm_err("Usually this is caused by manually changes, "
"please refer to http://linux-ha.org/v2/faq/cib_changes_detected");
crm_warn("Continuing but %s will NOT used.", filename);
free_xml(root);
root = NULL;
if(archive_invalid) {
int rc = 0;
char *suffix = crm_itoa(getpid());
/* Archive the original files so the contents are not lost */
crm_err("Archiving corrupt or unusable configuration to %s.%s", filename, suffix);
rc = archive_file(filename, NULL, suffix, TRUE);
if(rc < 0) {
crm_err("Archival of %s failed - Disabling disk writes and continuing", filename);
cib_writes_enabled = FALSE;
}
rc = archive_file(sigfile, NULL, suffix, TRUE);
if(rc < 0) {
crm_err("Archival of %s failed - Disabling disk writes and continuing", sigfile);
cib_writes_enabled = FALSE;
}
/* Unlink the original files so they dont get in the way later */
cib_unlink(filename);
cib_unlink(sigfile);
crm_free(suffix);
}
}
return root;
}
crm_data_t*
readCibXmlFile(const char *dir, const char *file, gboolean discard_status)
{
gboolean dtd_ok = TRUE;
char *filename = NULL, *sigfile = NULL;
const char *name = NULL;
const char *value = NULL;
const char *ignore_dtd = NULL;
const char *use_valgrind = getenv("HA_VALGRIND_ENABLED");
crm_data_t *root = NULL;
crm_data_t *status = NULL;
if(!crm_is_writable(dir, file, HA_CCMUSER, NULL, FALSE)) {
cib_status = cib_bad_permissions;
return NULL;
}
filename = crm_concat(dir, file, '/');
sigfile = crm_concat(filename, "sig", '.');
cib_status = cib_ok;
root = retrieveCib(filename, sigfile, TRUE);
if(root == NULL) {
char *tmp = NULL;
/* Try the backups */
tmp = filename;
filename = crm_concat(tmp, "last", '.');
crm_free(tmp);
tmp = sigfile;
sigfile = crm_concat(tmp, "last", '.');
crm_free(tmp);
crm_warn("Primary configuration corrupt or unusable, trying backup...");
root = retrieveCib(filename, sigfile, FALSE);
}
if(root == NULL) {
root = createEmptyCib();
crm_warn("Continuing with an empty configuration.");
} else {
crm_xml_add(root, "generated", XML_BOOLEAN_FALSE);
}
if(cib_writes_enabled && crm_is_true(use_valgrind)) {
cib_writes_enabled = FALSE;
crm_err("HA_VALGRIND_ENABLED: %s",
getenv("HA_VALGRIND_ENABLED"));
crm_err("*********************************************************");
crm_err("*** Disabling disk writes to avoid confusing Valgrind ***");
crm_err("*********************************************************");
}
status = find_xml_node(root, XML_CIB_TAG_STATUS, FALSE);
if(discard_status && status != NULL) {
/* strip out the status section if there is one */
free_xml_from_parent(root, status);
status = NULL;
}
if(status == NULL) {
create_xml_node(root, XML_CIB_TAG_STATUS);
}
/* Do this before DTD validation happens */
/* fill in some defaults */
name = XML_ATTR_GENERATION_ADMIN;
value = crm_element_value(root, name);
if(value == NULL) {
crm_warn("No value for %s was specified in the configuration.",
name);
crm_warn("The reccomended course of action is to shutdown,"
" run crm_verify and fix any errors it reports.");
crm_warn("We will default to zero and continue but may get"
" confused about which configuration to use if"
" multiple nodes are powered up at the same time.");
crm_xml_add_int(root, name, 0);
}
name = XML_ATTR_GENERATION;
value = crm_element_value(root, name);
if(value == NULL) {
crm_xml_add_int(root, name, 0);
}
name = XML_ATTR_NUMUPDATES;
value = crm_element_value(root, name);
if(value == NULL) {
crm_xml_add_int(root, name, 0);
}
/* unset these and require the DC/CCM to update as needed */
update_counters(__FILE__, __PRETTY_FUNCTION__, root);
xml_remove_prop(root, XML_ATTR_DC_UUID);
if(discard_status) {
crm_log_xml_info(root, "[on-disk]");
}
ignore_dtd = crm_element_value(root, "ignore_dtd");
- dtd_ok = validate_with_dtd(root, TRUE, HA_NOARCHDATAHBDIR"/crm.dtd");
+ dtd_ok = validate_with_dtd(root, TRUE, DTD_DIRECTORY"/crm.dtd");
if(dtd_ok == FALSE) {
- crm_err("CIB does not validate against "HA_NOARCHDATAHBDIR"/crm.dtd");
+ crm_err("CIB does not validate against "DTD_DIRECTORY"/crm.dtd");
if(ignore_dtd == NULL
&& crm_is_true(ignore_dtd) == FALSE) {
cib_status = cib_dtd_validation;
}
} else if(ignore_dtd == NULL) {
crm_notice("Enabling DTD validation on"
" the existing (sane) configuration");
crm_xml_add(root, "ignore_dtd", XML_BOOLEAN_FALSE);
}
if(do_id_check(root, NULL, TRUE, FALSE)) {
crm_err("%s does not contain a vaild configuration:"
" ID check failed",
filename);
cib_status = cib_id_check;
}
if (verifyCibXml(root) == FALSE) {
crm_err("%s does not contain a vaild configuration:"
" structure test failed",
filename);
cib_status = cib_bad_config;
}
crm_free(filename);
crm_free(sigfile);
return root;
}
/*
* The caller should never free the return value
*/
crm_data_t*
get_the_CIB(void)
{
return the_cib;
}
gboolean
uninitializeCib(void)
{
crm_data_t *tmp_cib = the_cib;
if(tmp_cib == NULL) {
crm_debug("The CIB has already been deallocated.");
return FALSE;
}
initialized = FALSE;
the_cib = NULL;
node_search = NULL;
resource_search = NULL;
constraint_search = NULL;
status_search = NULL;
crm_debug("Deallocating the CIB.");
free_xml(tmp_cib);
crm_debug("The CIB has been deallocated.");
return TRUE;
}
/*
* This method will not free the old CIB pointer or the new one.
* We rely on the caller to have saved a pointer to the old CIB
* and to free the old/bad one depending on what is appropriate.
*/
gboolean
initializeCib(crm_data_t *new_cib)
{
gboolean is_valid = TRUE;
crm_data_t *tmp_node = NULL;
if(new_cib == NULL) {
return FALSE;
}
xml_validate(new_cib);
tmp_node = get_object_root(XML_CIB_TAG_NODES, new_cib);
if (tmp_node == NULL) { is_valid = FALSE; }
tmp_node = get_object_root(XML_CIB_TAG_RESOURCES, new_cib);
if (tmp_node == NULL) { is_valid = FALSE; }
tmp_node = get_object_root(XML_CIB_TAG_CONSTRAINTS, new_cib);
if (tmp_node == NULL) { is_valid = FALSE; }
tmp_node = get_object_root(XML_CIB_TAG_CRMCONFIG, new_cib);
if (tmp_node == NULL) { is_valid = FALSE; }
tmp_node = get_object_root(XML_CIB_TAG_STATUS, new_cib);
if (is_valid && tmp_node == NULL) {
create_xml_node(new_cib, XML_CIB_TAG_STATUS);
}
if(is_valid == FALSE) {
crm_warn("CIB Verification failed");
return FALSE;
}
update_counters(__FILE__, __PRETTY_FUNCTION__, new_cib);
the_cib = new_cib;
initialized = TRUE;
return TRUE;
}
int
archive_file(const char *oldname, const char *newname, const char *ext, gboolean preserve)
{
/* move 'oldname' to 'newname' by creating a hard link to it
* and then removing the original hard link
*/
int rc = 0;
int res = 0;
struct stat tmp;
int s_res = 0;
char *backup_file = NULL;
static const char *back_ext = "bak";
/* calculate the backup name if required */
if(newname != NULL) {
backup_file = crm_strdup(newname);
} else {
int max_name_len = 1024;
crm_malloc0(backup_file, max_name_len);
if (ext == NULL) {
ext = back_ext;
}
snprintf(backup_file, max_name_len - 1, "%s.%s", oldname, ext);
}
if(backup_file == NULL || strlen(backup_file) == 0) {
crm_err("%s backup filename was %s",
newname == NULL?"calculated":"supplied",
backup_file == NULL?"null":"empty");
rc = -4;
}
s_res = stat(backup_file, &tmp);
/* move the old backup */
if (rc == 0 && s_res >= 0) {
if(preserve == FALSE) {
res = unlink(backup_file);
if (res < 0) {
cl_perror("Could not unlink %s", backup_file);
rc = -1;
}
} else {
crm_info("Archive file %s exists... backing it up first", backup_file);
res = archive_file(backup_file, NULL, NULL, preserve);
if (res < 0) {
return res;
}
}
}
s_res = stat(oldname, &tmp);
/* copy */
if (rc == 0 && s_res >= 0) {
res = link(oldname, backup_file);
if (res < 0) {
cl_perror("Could not create backup %s from %s",
backup_file, oldname);
rc = -2;
} else if(preserve) {
crm_info("%s archived as %s", oldname, backup_file);
} else {
crm_debug("%s archived as %s", oldname, backup_file);
}
}
crm_free(backup_file);
return rc;
}
/*
* This method will free the old CIB pointer on success and the new one
* on failure.
*/
int
activateCibXml(crm_data_t *new_cib, gboolean to_disk)
{
int error_code = cib_ok;
crm_data_t *saved_cib = the_cib;
const char *ignore_dtd = NULL;
crm_log_xml_debug_4(new_cib, "Attempting to activate CIB");
CRM_ASSERT(new_cib != saved_cib);
if(saved_cib != NULL) {
crm_validate_data(saved_cib);
}
ignore_dtd = crm_element_value(new_cib, "ignore_dtd");
if(
#if CRM_DEPRECATED_SINCE_2_0_4
ignore_dtd != NULL &&
#endif
crm_is_true(ignore_dtd) == FALSE
&& validate_with_dtd(
- new_cib, TRUE, HA_NOARCHDATAHBDIR"/crm.dtd") == FALSE) {
- crm_err("Updated CIB does not validate against "HA_NOARCHDATAHBDIR"/crm.dtd... ignoring");
+ new_cib, TRUE, DTD_DIRECTORY"/crm.dtd") == FALSE) {
+ crm_err("Updated CIB does not validate against "DTD_DIRECTORY"/crm.dtd... ignoring");
error_code = cib_dtd_validation;
}
if(error_code == cib_ok && initializeCib(new_cib) == FALSE) {
error_code = cib_ACTIVATION;
crm_err("Ignoring invalid or NULL CIB");
}
if(error_code != cib_ok) {
if(saved_cib != NULL) {
crm_warn("Reverting to last known CIB");
if (initializeCib(saved_cib) == FALSE) {
/* oh we are so dead */
crm_crit("Couldn't re-initialize the old CIB!");
cl_flush_logs();
exit(1);
}
} else {
crm_crit("Could not write out new CIB and no saved"
" version to revert to");
}
} else if(per_action_cib && cib_writes_enabled && cib_status == cib_ok) {
crm_err("Per-action CIB");
write_cib_contents(the_cib);
} else if(cib_writes_enabled && cib_status == cib_ok && to_disk) {
crm_debug_2("Triggering CIB write");
G_main_set_trigger(cib_writer);
}
if(the_cib != saved_cib && the_cib != new_cib) {
CRM_DEV_ASSERT(error_code != cib_ok);
CRM_DEV_ASSERT(the_cib == NULL);
}
if(the_cib != new_cib) {
free_xml(new_cib);
CRM_DEV_ASSERT(error_code != cib_ok);
}
if(the_cib != saved_cib) {
free_xml(saved_cib);
}
return error_code;
}
int
write_cib_contents(gpointer p)
{
int rc = 0;
gboolean need_archive = FALSE;
struct stat buf;
char *digest = NULL;
int exit_rc = LSB_EXIT_OK;
crm_data_t *cib_status_root = NULL;
/* we can scribble on "the_cib" here and not affect the parent */
const char *epoch = crm_element_value(the_cib, XML_ATTR_GENERATION);
const char *updates = crm_element_value(the_cib, XML_ATTR_NUMUPDATES);
const char *admin_epoch = crm_element_value(
the_cib, XML_ATTR_GENERATION_ADMIN);
need_archive = (stat(CIB_FILENAME, &buf) == 0);
if (need_archive) {
crm_debug("Archiving current version");
/* check the admin didnt modify it underneath us */
if(validate_on_disk_cib(CIB_FILENAME, NULL) == FALSE) {
crm_err("%s was manually modified while Heartbeat was active!",
CIB_FILENAME);
exit_rc = LSB_EXIT_GENERIC;
goto cleanup;
}
/* These calls leak, but we're in a separate process that will exit
* when the function does... so it's of no consequence
*/
CRM_ASSERT(retrieveCib(CIB_FILENAME, CIB_FILENAME".sig", FALSE) != NULL);
rc = archive_file(CIB_FILENAME, NULL, "last", FALSE);
if(rc != 0) {
crm_err("Could not make backup of the existing CIB: %d", rc);
exit_rc = LSB_EXIT_GENERIC;
goto cleanup;
}
rc = archive_file(CIB_FILENAME".sig", NULL, "last", FALSE);
if(rc != 0) {
crm_warn("Could not make backup of the existing CIB digest: %d",
rc);
}
CRM_ASSERT(retrieveCib(CIB_FILENAME, CIB_FILENAME".sig", FALSE) != NULL);
CRM_ASSERT(retrieveCib(CIB_FILENAME".last", CIB_FILENAME".sig.last", FALSE) != NULL);
crm_debug("Verified CIB archive");
}
/* Given that we discard the status section on startup
* there is no point writing it out in the first place
* since users just get confused by it
*
* Although, it does help me once in a while
*
* So delete the status section before we write it out
*/
if(p == NULL) {
cib_status_root = find_xml_node(the_cib, XML_CIB_TAG_STATUS, TRUE);
CRM_DEV_ASSERT(cib_status_root != NULL);
if(cib_status_root != NULL) {
free_xml_from_parent(the_cib, cib_status_root);
}
}
rc = write_xml_file(the_cib, CIB_FILENAME, FALSE);
crm_debug("Wrote CIB to disk");
if(rc <= 0) {
crm_err("Changes couldn't be written to disk");
exit_rc = LSB_EXIT_GENERIC;
goto cleanup;
}
digest = calculate_xml_digest(the_cib, FALSE, FALSE);
crm_info("Wrote version %s.%s.%s of the CIB to disk (digest: %s)",
admin_epoch?admin_epoch:"0",
epoch?epoch:"0", updates?updates:"0", digest);
rc = write_cib_digest(the_cib, digest);
crm_debug("Wrote digest to disk");
if(rc <= 0) {
crm_err("Digest couldn't be written to disk");
exit_rc = LSB_EXIT_GENERIC;
goto cleanup;
}
CRM_ASSERT(retrieveCib(CIB_FILENAME, CIB_FILENAME".sig", FALSE) != NULL);
if(need_archive) {
CRM_ASSERT(retrieveCib(CIB_FILENAME".last", CIB_FILENAME".sig.last", FALSE) != NULL);
}
crm_debug("Wrote and verified CIB");
cleanup:
crm_free(digest);
if(p == NULL) {
/* fork-and-write mode */
exit(exit_rc);
}
/* stand-alone mode */
return exit_rc;
}
gboolean
set_connected_peers(crm_data_t *xml_obj)
{
guint active = 0;
int current = 0;
char *peers_s = NULL;
const char *current_s = NULL;
if(xml_obj == NULL) {
return FALSE;
}
current_s = crm_element_value(xml_obj, XML_ATTR_NUMPEERS);
current = crm_parse_int(current_s, "0");
active = crm_active_peers(crm_proc_cib);
if(current != active) {
crm_malloc0(peers_s, 32);
snprintf(peers_s, 32, "%u", active);
crm_xml_add(xml_obj, XML_ATTR_NUMPEERS, peers_s);
crm_debug("We now have %s (%u) active peers", peers_s, active);
crm_free(peers_s);
return TRUE;
}
return FALSE;
}
gboolean
update_counters(const char *file, const char *fn, crm_data_t *xml_obj)
{
gboolean did_update = FALSE;
did_update = did_update || set_connected_peers(xml_obj);
if(did_update) {
do_crm_log(LOG_DEBUG, "Counters updated by %s", fn);
}
return did_update;
}
void GHFunc_count_peers(gpointer key, gpointer value, gpointer user_data)
{
int *active = user_data;
if(safe_str_eq(value, ONLINESTATUS)) {
(*active)++;
} else if(safe_str_eq(value, JOINSTATUS)) {
(*active)++;
}
}
diff --git a/cib/messages.c b/cib/messages.c
index 91604169c4..f59edd07e7 100644
--- a/cib/messages.c
+++ b/cib/messages.c
@@ -1,931 +1,931 @@
/*
* 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 <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <heartbeat.h>
#include <clplumbing/cl_log.h>
#include <time.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/msg.h>
#include <crm/common/xml.h>
#include <crm/common/cluster.h>
#include <cibio.h>
#include <cibmessages.h>
#include <cibprimatives.h>
#include <callbacks.h>
#include <notify.h>
#define MAX_DIFF_RETRY 5
extern const char *cib_our_uname;
extern gboolean syncd_once;
enum cib_errors revision_check(crm_data_t *cib_update, crm_data_t *cib_copy, int flags);
int get_revision(crm_data_t *xml_obj, int cur_revision);
enum cib_errors updateList(
crm_data_t *local_cib, crm_data_t *update_command, crm_data_t *failed,
int operation, const char *section);
gboolean check_generation(crm_data_t *newCib, crm_data_t *oldCib);
gboolean update_results(
crm_data_t *failed, crm_data_t *target, int operation, int return_code);
enum cib_errors cib_update_counter(
crm_data_t *xml_obj, const char *field, gboolean reset);
enum cib_errors sync_our_cib(HA_Message *request, gboolean all);
extern HA_Message *cib_msg_copy(const HA_Message *msg, gboolean with_data);
extern gboolean cib_shutdown_flag;
extern void terminate_cib(const char *caller);
enum cib_errors
cib_process_shutdown_req(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
enum cib_errors result = cib_ok;
const char *host = cl_get_string(input, F_ORIG);
*answer = NULL;
if(cl_get_string(input, F_CIB_ISREPLY) == NULL) {
crm_info("Shutdown REQ from %s", host);
return cib_ok;
} else if(cib_shutdown_flag) {
crm_info("Shutdown ACK from %s", host);
terminate_cib(__FUNCTION__);
return cib_ok;
} else {
crm_err("Shutdown ACK from %s - not shutting down",host);
result = cib_unknown;
}
return result;
}
enum cib_errors
cib_process_default(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event", op);
*answer = NULL;
if(op == NULL) {
result = cib_operation;
crm_err("No operation specified");
} else if(strcasecmp(CRM_OP_NOOP, op) == 0) {
;
} else {
result = cib_NOTSUPPORTED;
crm_err("Action [%s] is not supported by the CIB", op);
}
return result;
}
enum cib_errors
cib_process_quit(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event", op);
crm_warn("The CRMd has asked us to exit... complying");
exit(0);
return result;
}
enum cib_errors
cib_process_readwrite(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event", op);
if(safe_str_eq(op, CIB_OP_ISMASTER)) {
if(cib_is_master == TRUE) {
result = cib_ok;
} else {
result = cib_not_master;
}
return result;
}
if(safe_str_eq(op, CIB_OP_MASTER)) {
if(cib_is_master == FALSE) {
crm_info("We are now in R/W mode");
cib_is_master = TRUE;
syncd_once = TRUE;
} else {
crm_debug("We are still in R/W mode");
}
} else if(cib_is_master) {
crm_info("We are now in R/O mode");
cib_is_master = FALSE;
}
return result;
}
enum cib_errors
cib_process_ping(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event", op);
*answer = createPingAnswerFragment(CRM_SYSTEM_CIB, "ok");
return result;
}
enum cib_errors
cib_process_query(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
crm_data_t *obj_root = NULL;
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event for section=%s",
op, crm_str(section));
CRM_CHECK(*answer == NULL, free_xml(*answer));
*answer = NULL;
if (safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
section = NULL;
}
obj_root = get_object_root(section, existing_cib);
if(obj_root == NULL) {
result = cib_NOTEXISTS;
} else {
*answer = obj_root;
}
if(result == cib_ok && *answer == NULL) {
crm_err("Error creating query response");
result = cib_output_data;
}
return result;
}
enum cib_errors
cib_process_erase(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
crm_data_t *local_diff = NULL;
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event", op);
*answer = NULL;
free_xml(*result_cib);
*result_cib = createEmptyCib();
copy_in_properties(*result_cib, existing_cib);
cib_update_counter(*result_cib, XML_ATTR_GENERATION, FALSE);
local_diff = diff_cib_object(existing_cib, *result_cib, FALSE);
cib_replace_notify(*result_cib, result, local_diff);
free_xml(local_diff);
return result;
}
enum cib_errors
cib_process_bump(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event for epoch=%s",
op, crm_str(crm_element_value(the_cib, XML_ATTR_GENERATION)));
*answer = NULL;
cib_update_counter(*result_cib, XML_ATTR_GENERATION, FALSE);
return result;
}
enum cib_errors
cib_process_sync(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
return sync_our_cib(input, TRUE);
}
enum cib_errors
cib_process_sync_one(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
return sync_our_cib(input, FALSE);
}
enum cib_errors
cib_update_counter(crm_data_t *xml_obj, const char *field, gboolean reset)
{
char *new_value = NULL;
char *old_value = NULL;
int int_value = -1;
if(reset == FALSE && crm_element_value(xml_obj, field) != NULL) {
old_value = crm_element_value_copy(xml_obj, field);
}
if(old_value != NULL) {
crm_malloc0(new_value, 128);
int_value = atoi(old_value);
sprintf(new_value, "%d", ++int_value);
} else {
new_value = crm_strdup("1");
}
crm_debug_4("%s %d(%s)->%s",
field, int_value, crm_str(old_value), crm_str(new_value));
crm_xml_add(xml_obj, field, new_value);
crm_free(new_value);
crm_free(old_value);
return cib_ok;
}
int sync_in_progress = 0;
enum cib_errors
cib_process_diff(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
unsigned int log_level = LOG_DEBUG;
const char *value = NULL;
const char *reason = NULL;
gboolean apply_diff = TRUE;
gboolean do_resync = FALSE;
enum cib_errors result = cib_ok;
int this_updates = 0;
int this_epoch = 0;
int this_admin_epoch = 0;
int diff_add_updates = 0;
int diff_add_epoch = 0;
int diff_add_admin_epoch = 0;
int diff_del_updates = 0;
int diff_del_epoch = 0;
int diff_del_admin_epoch = 0;
crm_debug_2("Processing \"%s\" event", op);
if(cib_is_master) {
/* the master is never waiting for a resync */
sync_in_progress = 0;
}
cib_diff_version_details(
input,
&diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
&diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
if(sync_in_progress > MAX_DIFF_RETRY) {
/* request another full-sync,
* the last request may have been lost
*/
sync_in_progress = 0;
}
if(sync_in_progress) {
sync_in_progress++;
crm_warn("Not applying diff %d.%d.%d -> %d.%d.%d (sync in progress)",
diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
diff_add_admin_epoch,diff_add_epoch,diff_add_updates);
return cib_diff_resync;
}
value = crm_element_value(existing_cib, XML_ATTR_GENERATION);
this_epoch = atoi(value?value:"0");
value = crm_element_value(existing_cib, XML_ATTR_NUMUPDATES);
this_updates = atoi(value?value:"0");
value = crm_element_value(existing_cib, XML_ATTR_GENERATION_ADMIN);
this_admin_epoch = atoi(value?value:"0");
if(diff_del_admin_epoch == diff_add_admin_epoch
&& diff_del_epoch == diff_add_epoch
&& diff_del_updates == diff_add_updates) {
if(diff_add_admin_epoch == -1 && diff_add_epoch == -1 && diff_add_updates == -1) {
diff_add_epoch = this_epoch;
diff_add_updates = this_updates + 1;
diff_add_admin_epoch = this_admin_epoch;
diff_del_epoch = this_epoch;
diff_del_updates = this_updates;
diff_del_admin_epoch = this_admin_epoch;
} else {
apply_diff = FALSE;
log_level = LOG_ERR;
reason = "+ and - versions in the diff did not change";
log_cib_diff(LOG_ERR, input, __FUNCTION__);
}
}
if(apply_diff && diff_del_admin_epoch > this_admin_epoch) {
do_resync = TRUE;
apply_diff = FALSE;
log_level = LOG_INFO;
reason = "current \""XML_ATTR_GENERATION_ADMIN"\" is less than required";
} else if(apply_diff && diff_del_admin_epoch < this_admin_epoch) {
apply_diff = FALSE;
log_level = LOG_WARNING;
reason = "current \""XML_ATTR_GENERATION_ADMIN"\" is greater than required";
}
if(apply_diff && diff_del_epoch > this_epoch) {
do_resync = TRUE;
apply_diff = FALSE;
log_level = LOG_INFO;
reason = "current \""XML_ATTR_GENERATION"\" is less than required";
} else if(apply_diff && diff_del_epoch < this_epoch) {
apply_diff = FALSE;
log_level = LOG_WARNING;
reason = "current \""XML_ATTR_GENERATION"\" is greater than required";
}
if(apply_diff && diff_del_updates > this_updates) {
do_resync = TRUE;
apply_diff = FALSE;
log_level = LOG_INFO;
reason = "current \""XML_ATTR_NUMUPDATES"\" is less than required";
} else if(apply_diff && diff_del_updates < this_updates) {
apply_diff = FALSE;
log_level = LOG_WARNING;
reason = "current \""XML_ATTR_NUMUPDATES"\" is greater than required";
}
if(apply_diff) {
free_xml(*result_cib);
*result_cib = NULL;
if(apply_xml_diff(existing_cib, input, result_cib) == FALSE) {
log_level = LOG_WARNING;
reason = "Failed application of an update diff";
if(options & cib_force_diff) {
if(cib_is_master == FALSE) {
log_level = LOG_INFO;
reason = "Failed application of a global update."
" Requesting full refresh.";
do_resync = TRUE;
} else {
reason = "Failed application of a global update."
" Not requesting full refresh.";
}
}
} else if((options & cib_force_diff) && !validate_with_dtd(
- *result_cib, FALSE, HA_NOARCHDATAHBDIR"/crm.dtd")) {
+ *result_cib, FALSE, DTD_DIRECTORY"/crm.dtd")) {
if(cib_is_master == FALSE) {
log_level = LOG_INFO;
reason = "Failed DTD validation of a global update."
" Requesting full refresh.";
do_resync = TRUE;
} else {
log_level = LOG_WARNING;
reason = "Failed DTD validation of a global update."
" Not requesting full refresh.";
}
}
}
if(reason != NULL) {
do_crm_log(
log_level,
"Diff %d.%d.%d -> %d.%d.%d not applied to %d.%d.%d: %s",
diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
diff_add_admin_epoch,diff_add_epoch,diff_add_updates,
this_admin_epoch,this_epoch,this_updates, reason);
result = cib_diff_failed;
} else if(apply_diff) {
crm_debug_2("Diff %d.%d.%d -> %d.%d.%d was applied",
diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
diff_add_admin_epoch,diff_add_epoch,diff_add_updates);
}
if(do_resync && cib_is_master == FALSE) {
HA_Message *sync_me = ha_msg_new(3);
free_xml(*result_cib);
*result_cib = NULL;
result = cib_diff_resync;
crm_info("Requesting re-sync from peer: %s", reason);
sync_in_progress++;
ha_msg_add(sync_me, F_TYPE, "cib");
ha_msg_add(sync_me, F_CIB_OPERATION, CIB_OP_SYNC_ONE);
ha_msg_add(sync_me, F_CIB_DELEGATED, cib_our_uname);
if(send_cluster_message(NULL, crm_msg_cib, sync_me, FALSE) == FALSE) {
result = cib_not_connected;
}
ha_msg_del(sync_me);
} else if(do_resync) {
crm_warn("Not resyncing in master mode");
}
return result;
}
enum cib_errors
cib_process_replace(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
const char *tag = NULL;
gboolean send_notify = FALSE;
gboolean verbose = FALSE;
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event for section=%s",
op, crm_str(section));
*answer = NULL;
if (input == NULL) {
return cib_NOOBJECT;
}
tag = crm_element_name(input);
if (options & cib_verbose) {
verbose = TRUE;
}
if(safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
section = NULL;
} else if(safe_str_eq(tag, section)) {
section = NULL;
}
if(safe_str_eq(tag, XML_TAG_CIB)) {
int updates = 0;
int epoch = 0;
int admin_epoch = 0;
int replace_updates = 0;
int replace_epoch = 0;
int replace_admin_epoch = 0;
const char *reason = NULL;
cib_version_details(
existing_cib, &admin_epoch, &epoch, &updates);
cib_version_details(input, &replace_admin_epoch,
&replace_epoch, &replace_updates);
if(replace_admin_epoch < admin_epoch) {
reason = XML_ATTR_GENERATION_ADMIN;
} else if(replace_admin_epoch > admin_epoch) {
/* no more checks */
} else if(replace_epoch < epoch) {
reason = XML_ATTR_GENERATION;
} else if(replace_epoch > epoch) {
/* no more checks */
} else if(replace_updates < updates) {
reason = XML_ATTR_NUMUPDATES;
}
if(reason != NULL) {
crm_warn("Replacement %d.%d.%d not applied to %d.%d.%d:"
" current %s is greater than the replacement",
replace_admin_epoch, replace_epoch,
replace_updates, admin_epoch, epoch, updates,
reason);
result = cib_old_data;
}
sync_in_progress = 0;
free_xml(*result_cib);
*result_cib = copy_xml(input);
send_notify = TRUE;
} else {
crm_data_t *obj_root = NULL;
gboolean ok = TRUE;
obj_root = get_object_root(section, *result_cib);
ok = replace_xml_child(NULL, obj_root, input, FALSE);
if(ok == FALSE) {
crm_debug_2("No matching object to replace");
result = cib_NOTEXISTS;
} else if(safe_str_eq(section, XML_CIB_TAG_NODES)) {
send_notify = TRUE;
} else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) {
send_notify = TRUE;
} else if(safe_str_eq(tag, XML_CIB_TAG_STATUS)) {
send_notify = TRUE;
} else if(safe_str_eq(tag, XML_CIB_TAG_NODES)) {
send_notify = TRUE;
}
}
if(send_notify) {
crm_data_t *local_diff = NULL;
local_diff = diff_cib_object(existing_cib, *result_cib, FALSE);
cib_replace_notify(*result_cib, result, local_diff);
free_xml(local_diff);
}
return result;
}
enum cib_errors
cib_process_delete(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
crm_data_t *obj_root = NULL;
crm_debug_2("Processing \"%s\" event", op);
if(input == NULL) {
crm_err("Cannot perform modification with no data");
return cib_NOOBJECT;
}
obj_root = get_object_root(section, *result_cib);
crm_validate_data(input);
crm_validate_data(*result_cib);
if(replace_xml_child(NULL, obj_root, input, TRUE) == FALSE) {
crm_debug_2("No matching object to delete");
}
return cib_ok;
}
enum cib_errors
cib_process_modify(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
crm_data_t *obj_root = NULL;
crm_debug_2("Processing \"%s\" event", op);
if(input == NULL) {
crm_err("Cannot perform modification with no data");
return cib_NOOBJECT;
}
obj_root = get_object_root(section, *result_cib);
crm_validate_data(input);
crm_validate_data(*result_cib);
if(update_xml_child(obj_root, input) == FALSE) {
return cib_NOTEXISTS;
}
return cib_ok;
}
enum cib_errors
cib_process_change(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
gboolean verbose = FALSE;
crm_data_t *failed = NULL;
enum cib_errors result = cib_ok;
int cib_update_op = CIB_UPDATE_OP_NONE;
crm_debug_2("Processing \"%s\" event for section=%s", op, crm_str(section));
if (strcasecmp(CIB_OP_CREATE, op) == 0) {
cib_update_op = CIB_UPDATE_OP_ADD;
} else if (strcasecmp(CIB_OP_UPDATE, op) == 0) {
cib_update_op = CIB_UPDATE_OP_MODIFY;
} else if (strcasecmp(CIB_OP_DELETE_ALT, op) == 0) {
cib_update_op = CIB_UPDATE_OP_DELETE;
} else {
crm_err("Incorrect request handler invoked for \"%s\" op",
crm_str(op));
return cib_operation;
}
result = cib_ok;
if (options & cib_verbose) {
verbose = TRUE;
}
if(safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
section = NULL;
} else if(safe_str_eq(XML_TAG_CIB, section)) {
section = NULL;
}
if(input == NULL) {
crm_err("Cannot perform modification with no data");
return cib_NOOBJECT;
}
crm_validate_data(input);
crm_validate_data(*result_cib);
failed = create_xml_node(NULL, XML_TAG_FAILED);
/* make changes to a temp copy then activate */
if(section == NULL) {
int lpc = 0;
const char *type = NULL;
crm_data_t *sub_input = NULL;
/* order is no longer important here */
const char *type_list[] = {
XML_CIB_TAG_NODES,
XML_CIB_TAG_CONSTRAINTS,
XML_CIB_TAG_RESOURCES,
XML_CIB_TAG_STATUS,
XML_CIB_TAG_CRMCONFIG
};
copy_in_properties(*result_cib, input);
for(lpc = 0; lpc < DIMOF(type_list); lpc++) {
type = type_list[lpc];
if(result == cib_ok) {
crm_debug_2("Processing section=%s", type);
sub_input = get_object_root(type, input);
if(sub_input) {
result = updateList(
*result_cib, sub_input, failed,
cib_update_op, type);
}
}
}
} else {
result = updateList(
*result_cib, input, failed, cib_update_op, section);
}
if (result != cib_ok || xml_has_children(failed)) {
if(result == cib_ok) {
result = cib_unknown;
}
crm_log_xml_err(failed, "CIB Update failures");
*answer = failed;
} else {
free_xml(failed);
}
return result;
}
#define cib_update_xml_macro(parent, xml_update) \
if(operation == CIB_UPDATE_OP_DELETE) { \
rc = delete_cib_object(parent, xml_update); \
update_results(failed, xml_update, operation, rc); \
\
} else if(operation == CIB_UPDATE_OP_MODIFY) { \
rc = update_cib_object(parent, xml_update); \
update_results(failed, xml_update, operation, rc); \
\
} else { \
rc = add_cib_object(parent, xml_update); \
update_results(failed, xml_update, operation, rc); \
} \
enum cib_errors
updateList(crm_data_t *local_cib, crm_data_t *xml_section, crm_data_t *failed,
int operation, const char *section)
{
int rc = cib_ok;
crm_data_t *this_section = get_object_root(section, local_cib);
if (section == NULL || xml_section == NULL) {
crm_err("Section %s not found in message."
" CIB update is corrupt, ignoring.",
crm_str(section));
return cib_NOSECTION;
}
if((CIB_UPDATE_OP_NONE > operation)
|| (operation > CIB_UPDATE_OP_MAX)){
crm_err("Invalid operation on section %s", crm_str(section));
return cib_operation;
}
if(safe_str_eq(crm_element_name(xml_section), section)) {
xml_child_iter(xml_section, a_child,
rc = cib_ok;
cib_update_xml_macro(this_section, a_child);
);
} else {
cib_update_xml_macro(this_section, xml_section);
}
if(rc == cib_ok && xml_has_children(failed)) {
rc = cib_unknown;
}
return rc;
}
gboolean
check_generation(crm_data_t *newCib, crm_data_t *oldCib)
{
if(cib_compare_generation(newCib, oldCib) >= 0) {
return TRUE;
}
crm_warn("Generation from update is older than the existing one");
return FALSE;
}
gboolean
update_results(
crm_data_t *failed, crm_data_t *target, int operation, int return_code)
{
gboolean was_error = FALSE;
const char *error_msg = NULL;
const char *operation_msg = NULL;
crm_data_t *xml_node = NULL;
if (return_code != cib_ok) {
operation_msg = cib_op2string(operation);
error_msg = cib_error2string(return_code);
xml_node = create_xml_node(failed, XML_FAIL_TAG_CIB);
was_error = TRUE;
add_node_copy(xml_node, target);
crm_xml_add(xml_node, XML_FAILCIB_ATTR_ID, ID(target));
crm_xml_add(xml_node, XML_FAILCIB_ATTR_OBJTYPE, TYPE(target));
crm_xml_add(xml_node, XML_FAILCIB_ATTR_OP, operation_msg);
crm_xml_add(xml_node, XML_FAILCIB_ATTR_REASON, error_msg);
crm_warn("Action %s failed: %s (cde=%d)",
operation_msg, error_msg, return_code);
}
return was_error;
}
enum cib_errors
revision_check(crm_data_t *cib_update, crm_data_t *cib_copy, int flags)
{
int cmp = 0;
enum cib_errors rc = cib_ok;
char *new_revision = NULL;
const char *cur_revision = crm_element_value(
cib_copy, XML_ATTR_CIB_REVISION);
crm_validate_data(cib_update);
crm_validate_data(cib_copy);
if(crm_element_value(cib_update, XML_ATTR_CIB_REVISION) == NULL) {
return cib_ok;
}
new_revision = crm_element_value_copy(cib_update,XML_ATTR_CIB_REVISION);
cmp = compare_version(new_revision, CIB_FEATURE_SET);
if(cmp > 0) {
CRM_DEV_ASSERT(cib_is_master == FALSE);
CRM_DEV_ASSERT((flags & cib_scope_local) == 0);
if(cib_is_master) {
crm_err("Update uses an unsupported tag/feature:"
" %s vs %s", new_revision,CIB_FEATURE_SET);
rc = cib_revision_unsupported;
} else if(flags & cib_scope_local) {
/* an admin has forced a local change using a tag we
* dont understand... ERROR
*/
crm_err("Local update uses an unsupported tag/feature:"
" %s vs %s", new_revision,CIB_FEATURE_SET);
rc = cib_revision_unsupported;
}
} else if(cur_revision == NULL) {
crm_info("Updating CIB revision to %s", new_revision);
crm_xml_add(cib_copy, XML_ATTR_CIB_REVISION, new_revision);
} else {
/* make sure we end up with the right value in the end */
crm_xml_add(cib_update, XML_ATTR_CIB_REVISION, cur_revision);
}
crm_free(new_revision);
return rc;
}
enum cib_errors
sync_our_cib(HA_Message *request, gboolean all)
{
enum cib_errors result = cib_ok;
const char *host = cl_get_string(request, F_ORIG);
const char *op = cl_get_string(request, F_CIB_OPERATION);
HA_Message *replace_request = cib_msg_copy(request, FALSE);
CRM_CHECK(the_cib != NULL, ;);
CRM_CHECK(replace_request != NULL, ;);
crm_info("Syncing CIB to %s", all?"all peers":host);
if(all == FALSE && host == NULL) {
crm_log_message(LOG_ERR, request);
}
/* remove the "all == FALSE" condition
*
* sync_from was failing, the local client wasnt being notified
* because it didnt know it was a reply
* setting this does not prevent the other nodes from applying it
* if all == TRUE
*/
if(host != NULL) {
ha_msg_add(replace_request, F_CIB_ISREPLY, host);
}
ha_msg_mod(replace_request, F_CIB_OPERATION, CIB_OP_REPLACE);
ha_msg_add(replace_request, "original_"F_CIB_OPERATION, op);
ha_msg_add(replace_request, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE);
add_message_xml(replace_request, F_CIB_CALLDATA, the_cib);
if(send_cluster_message(all?NULL:host, crm_msg_cib, replace_request, FALSE) == FALSE) {
result = cib_not_connected;
}
ha_msg_del(replace_request);
return result;
}
diff --git a/crm/admin/crm_verify.c b/crm/admin/crm_verify.c
index 95a8de6740..f1ba607778 100644
--- a/crm/admin/crm_verify.c
+++ b/crm/admin/crm_verify.c
@@ -1,320 +1,320 @@
/*
* 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 <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/common/xml.h>
#include <crm/common/util.h>
#include <crm/msg_xml.h>
#include <clplumbing/cl_signal.h>
#include <crm/cib.h>
#include <clplumbing/lsb_exitcodes.h>
#define OPTARGS "V?X:x:pLS:D:"
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
#include <glib.h>
#include <crm/pengine/status.h>
gboolean USE_LIVE_CIB = FALSE;
char *cib_save = NULL;
void usage(const char *cmd, int exit_status);
extern gboolean stage0(pe_working_set_t *data_set);
extern void cleanup_alloc_calculations(pe_working_set_t *data_set);
extern crm_data_t * do_calculations(
pe_working_set_t *data_set, crm_data_t *xml_input, ha_time_t *now);
-const char *dtd_file = HA_NOARCHDATAHBDIR"/crm.dtd";
+const char *dtd_file = DTD_DIRECTORY"/crm.dtd";
int
main(int argc, char **argv)
{
crm_data_t *cib_object = NULL;
crm_data_t *status = NULL;
int argerr = 0;
int flag;
pe_working_set_t data_set;
cib_t * cib_conn = NULL;
int rc = cib_ok;
gboolean xml_stdin = FALSE;
const char *xml_file = NULL;
const char *xml_string = NULL;
g_log_set_handler(NULL,
G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL
| G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE
| G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG
| G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL,
cl_glib_msg_handler, NULL);
/* and for good measure... - this enum is a bit field (!) */
g_log_set_always_fatal((GLogLevelFlags)0); /*value out of range*/
crm_log_init(basename(argv[0]), LOG_ERR, FALSE, TRUE, 0, NULL);
CL_SIGNAL(DEBUG_INC, alter_debug);
CL_SIGNAL(DEBUG_DEC, alter_debug);
while (1) {
#ifdef HAVE_GETOPT_H
int option_index = 0;
static struct option long_options[] = {
/* Top-level Options */
{F_CRM_DATA, 1, 0, 'X'},
{"dtd-file", 1, 0, 'D'},
{"xml-file", 1, 0, 'x'},
{"xml-pipe", 0, 0, 'p'},
{"save-xml", 1, 0, 'S'},
{"live-check", 0, 0, 'L'},
{"help", 0, 0, '?'},
{0, 0, 0, 0}
};
#endif
#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) {
#ifdef HAVE_GETOPT_H
case 0:
printf("option %s", long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
break;
#endif
case 'D':
crm_debug_2("Option %c => %s", flag, optarg);
dtd_file = optarg;
break;
case 'X':
crm_debug_2("Option %c => %s", flag, optarg);
xml_string = crm_strdup(optarg);
break;
case 'x':
crm_debug_2("Option %c => %s", flag, optarg);
xml_file = crm_strdup(optarg);
break;
case 'p':
xml_stdin = TRUE;
break;
case 'S':
cib_save = crm_strdup(optarg);
break;
case 'V':
alter_debug(DEBUG_INC);
break;
case 'L':
USE_LIVE_CIB = TRUE;
break;
case '?':
usage(crm_system_name, LSB_EXIT_GENERIC);
break;
default:
printf("?? getopt returned character code 0%o ??\n", flag);
++argerr;
break;
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc) {
printf("%s ", argv[optind++]);
}
printf("\n");
}
if (optind > argc) {
++argerr;
}
if (argerr) {
crm_err("%d errors in option parsing", argerr);
usage(crm_system_name, LSB_EXIT_GENERIC);
}
crm_info("=#=#=#=#= Getting XML =#=#=#=#=");
if(USE_LIVE_CIB) {
cib_conn = cib_new();
rc = cib_conn->cmds->signon(
cib_conn, crm_system_name, cib_command_synchronous);
}
if(USE_LIVE_CIB) {
if(rc == cib_ok) {
int options = cib_scope_local|cib_sync_call;
crm_info("Reading XML from: live cluster");
rc = cib_conn->cmds->query(
cib_conn, NULL, &cib_object, options);
}
if(rc != cib_ok) {
fprintf(stderr, "Live CIB query failed: %s\n",
cib_error2string(rc));
return 3;
}
if(cib_object == NULL) {
fprintf(stderr, "Live CIB query failed: empty result\n");
return 3;
}
} else if(xml_file != NULL) {
FILE *xml_strm = fopen(xml_file, "r");
cib_object = file2xml(xml_strm, FALSE);
if(cib_object == NULL) {
fprintf(stderr,
"Couldn't parse input file: %s\n", xml_file);
return 1;
}
fclose(xml_strm);
} else if(xml_string != NULL) {
cib_object = string2xml(xml_string);
if(cib_object == NULL) {
fprintf(stderr,
"Couldn't parse input string: %s\n", xml_string);
return 1;
}
} else if(xml_stdin) {
cib_object = stdin2xml();
if(cib_object == NULL) {
fprintf(stderr, "Couldn't parse input from STDIN.\n");
return 1;
}
} else {
fprintf(stderr, "No configuration source specified."
" Use --help for usage information.\n");
return 3;
}
if(cib_save != NULL) {
write_xml_file(cib_object, cib_save, FALSE);
}
status = get_object_root(XML_CIB_TAG_STATUS, cib_object);
if(status == NULL) {
create_xml_node(cib_object, XML_CIB_TAG_STATUS);
}
#if CRM_DEPRECATED_SINCE_2_0_4
xml_child_iter_filter(status, node_state, XML_CIB_TAG_STATE,
xml_remove_prop(node_state, XML_CIB_TAG_LRM);
);
#endif
crm_notice("Required feature set: %s", feature_set(cib_object));
if(do_id_check(cib_object, NULL, FALSE, FALSE)) {
crm_config_err("ID Check failed");
}
if(validate_with_dtd(cib_object, FALSE, dtd_file) == FALSE) {
crm_config_err("CIB did not pass DTD validation");
}
if(USE_LIVE_CIB) {
/* we will always have a status section and can do a full simulation */
do_calculations(&data_set, cib_object, NULL);
} else {
set_working_set_defaults(&data_set);
data_set.now = new_ha_date(TRUE);
data_set.input = cib_object;
stage0(&data_set);
}
cleanup_alloc_calculations(&data_set);
if(crm_config_error) {
fprintf(stderr, "Errors found during check: config not valid\n");
if(crm_log_level < LOG_WARNING) {
fprintf(stderr, " -V may provide more details\n");
}
rc = 2;
} else if(crm_config_warning) {
fprintf(stderr, "Warnings found during check: config may not be valid\n");
if(crm_log_level < LOG_WARNING) {
fprintf(stderr, " Use -V for more details\n");
}
rc = 1;
}
if(USE_LIVE_CIB) {
cib_conn->cmds->signoff(cib_conn);
cib_delete(cib_conn);
}
return rc;
}
void
usage(const char *cmd, int exit_status)
{
FILE *stream;
stream = exit_status ? stderr : stdout;
fprintf(stream, "usage: %s [-V] [-D] -(?|L|X|x|p)\n", cmd);
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: Connect to the running cluster\n",
"live-check", 'L');
fprintf(stream, "\t--%s (-%c) <string>\t: Use the configuration in the supplied string\n",
F_CRM_DATA, 'X');
fprintf(stream, "\t--%s (-%c) <file>\t: Use the configuration in the named file\n",
"xml-file", 'x');
fprintf(stream, "\t--%s (-%c) \t: Use the configuration piped in via stdin\n",
"xml-pipe", 'p');
fprintf(stream, "\t--%s (-%c) \t: Use the named dtd file instead of %s\n",
"dtd-file", 'D', dtd_file);
fflush(stream);
exit(exit_status);
}
diff --git a/lib/crm/cib/cib_client.c b/lib/crm/cib/cib_client.c
index 161418d222..263b4c9a02 100644
--- a/lib/crm/cib/cib_client.c
+++ b/lib/crm/cib/cib_client.c
@@ -1,1600 +1,1600 @@
/*
* Copyright (c) 2004 International Business Machines
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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 library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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 <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <glib.h>
#include <heartbeat.h>
#include <clplumbing/ipc.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <cib_private.h>
/* short term hack to reduce callback messages */
typedef struct cib_native_opaque_s
{
IPC_Channel *command_channel;
IPC_Channel *callback_channel;
GCHSource *callback_source;
} cib_native_opaque_t;
GHashTable *cib_op_callback_table = NULL;
gboolean verify_cib_cmds(cib_t *cib);
int cib_client_set_op_callback(
cib_t *cib, void (*callback)(const struct ha_msg *msg, int call_id,
int rc, crm_data_t *output));
int cib_client_noop(cib_t *cib, int call_options);
int cib_client_ping(cib_t *cib, crm_data_t **output_data, int call_options);
int cib_client_query(cib_t *cib, const char *section,
crm_data_t **output_data, int call_options);
int cib_client_query_from(cib_t *cib, const char *host, const char *section,
crm_data_t **output_data, int call_options);
int cib_client_sync(cib_t *cib, const char *section, int call_options);
int cib_client_sync_from(
cib_t *cib, const char *host, const char *section, int call_options);
int cib_client_is_master(cib_t *cib);
int cib_client_set_slave(cib_t *cib, int call_options);
int cib_client_set_slave_all(cib_t *cib, int call_options);
int cib_client_set_master(cib_t *cib, int call_options);
int cib_client_bump_epoch(cib_t *cib, int call_options);
int cib_client_create(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options);
int cib_client_modify(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options);
int cib_client_update(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options);
int cib_client_replace(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options);
int cib_client_delete(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options);
int cib_client_delete_absolute(
cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options);
int cib_client_erase(
cib_t *cib, crm_data_t **output_data, int call_options);
int cib_client_quit(cib_t *cib, int call_options);
int cib_client_add_notify_callback(
cib_t *cib, const char *event, void (*callback)(
const char *event, struct ha_msg *msg));
int cib_client_del_notify_callback(
cib_t *cib, const char *event, void (*callback)(
const char *event, struct ha_msg *msg));
gint ciblib_GCompareFunc(gconstpointer a, gconstpointer b);
extern cib_t *cib_native_new(cib_t *cib);
extern void cib_native_delete(cib_t *cib);
static enum cib_variant configured_variant = cib_native;
/* define of the api functions*/
cib_t*
cib_new(void)
{
cib_t* new_cib = NULL;
if(configured_variant != cib_native) {
crm_err("Only the native CIB type is currently implemented");
return NULL;
}
if(cib_op_callback_table != NULL) {
g_hash_table_destroy(cib_op_callback_table);
cib_op_callback_table = NULL;
}
if(cib_op_callback_table == NULL) {
cib_op_callback_table = g_hash_table_new_full(
g_direct_hash, g_direct_equal,
NULL, g_hash_destroy_str);
}
crm_malloc0(new_cib, sizeof(cib_t));
new_cib->call_id = 1;
new_cib->type = cib_none;
new_cib->state = cib_disconnected;
new_cib->op_callback = NULL;
new_cib->variant_opaque = NULL;
new_cib->notify_list = NULL;
/* the rest will get filled in by the variant constructor */
crm_malloc0(new_cib->cmds, sizeof(cib_api_operations_t));
new_cib->cmds->set_op_callback = cib_client_set_op_callback;
new_cib->cmds->add_notify_callback = cib_client_add_notify_callback;
new_cib->cmds->del_notify_callback = cib_client_del_notify_callback;
new_cib->cmds->noop = cib_client_noop;
new_cib->cmds->ping = cib_client_ping;
new_cib->cmds->query = cib_client_query;
new_cib->cmds->sync = cib_client_sync;
new_cib->cmds->query_from = cib_client_query_from;
new_cib->cmds->sync_from = cib_client_sync_from;
new_cib->cmds->is_master = cib_client_is_master;
new_cib->cmds->set_master = cib_client_set_master;
new_cib->cmds->set_slave = cib_client_set_slave;
new_cib->cmds->set_slave_all = cib_client_set_slave_all;
new_cib->cmds->bump_epoch = cib_client_bump_epoch;
new_cib->cmds->create = cib_client_create;
new_cib->cmds->modify = cib_client_modify;
new_cib->cmds->update = cib_client_update;
new_cib->cmds->replace = cib_client_replace;
new_cib->cmds->delete = cib_client_delete;
new_cib->cmds->erase = cib_client_erase;
new_cib->cmds->quit = cib_client_quit;
new_cib->cmds->delete_absolute = cib_client_delete_absolute;
cib_native_new(new_cib);
if(verify_cib_cmds(new_cib) == FALSE) {
cib_delete(new_cib);
return NULL;
}
return new_cib;
}
void
cib_delete(cib_t *cib)
{
GList *list = cib->notify_list;
while(list != NULL) {
cib_notify_client_t *client = g_list_nth_data(list, 0);
list = g_list_remove(list, client);
crm_free(client);
}
cib_native_delete(cib);
g_hash_table_destroy(cib_op_callback_table);
crm_free(cib->cmds);
crm_free(cib);
}
int
cib_client_set_op_callback(
cib_t *cib, void (*callback)(const struct ha_msg *msg, int call_id,
int rc, crm_data_t *output))
{
if(callback == NULL) {
crm_info("Un-Setting operation callback");
} else {
crm_debug_3("Setting operation callback");
}
cib->op_callback = callback;
return cib_ok;
}
int cib_client_noop(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CRM_OP_NOOP, NULL, NULL, NULL, NULL, call_options);
}
int cib_client_ping(cib_t *cib, crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CRM_OP_PING, NULL,NULL,NULL, output_data, call_options);
}
int cib_client_query(cib_t *cib, const char *section,
crm_data_t **output_data, int call_options)
{
return cib->cmds->query_from(
cib, NULL, section, output_data, call_options);
}
int cib_client_query_from(cib_t *cib, const char *host, const char *section,
crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CIB_OP_QUERY, host, section,
NULL, output_data, call_options);
}
int cib_client_is_master(cib_t *cib)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CIB_OP_ISMASTER, NULL, NULL,NULL,NULL,
cib_scope_local|cib_sync_call);
}
int cib_client_set_slave(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CIB_OP_SLAVE, NULL,NULL,NULL,NULL, call_options);
}
int cib_client_set_slave_all(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CIB_OP_SLAVEALL, NULL,NULL,NULL,NULL, call_options);
}
int cib_client_set_master(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
crm_debug_3("Adding cib_scope_local to options");
return cib->cmds->variant_op(
cib, CIB_OP_MASTER, NULL,NULL,NULL,NULL,
call_options|cib_scope_local);
}
int cib_client_bump_epoch(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CIB_OP_BUMP, NULL, NULL, NULL, NULL, call_options);
}
int cib_client_sync(cib_t *cib, const char *section, int call_options)
{
return cib->cmds->sync_from(cib, NULL, section, call_options);
}
int cib_client_sync_from(
cib_t *cib, const char *host, const char *section, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CIB_OP_SYNC, host, section, NULL, NULL, call_options);
}
int cib_client_create(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CIB_OP_CREATE, NULL, section,
data, output_data, call_options);
}
int cib_client_modify(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CIB_OP_MODIFY, NULL, section,
data, output_data, call_options);
}
int cib_client_update(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CIB_OP_UPDATE, NULL, section,
data, output_data, call_options);
}
int cib_client_replace(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
} else if(data == NULL) {
return cib_missing_data;
}
return cib->cmds->variant_op(cib, CIB_OP_REPLACE, NULL, section,
data, output_data, call_options);
}
int cib_client_delete(cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CIB_OP_DELETE, NULL, section,
data, output_data, call_options);
}
int cib_client_delete_absolute(
cib_t *cib, const char *section, crm_data_t *data,
crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CIB_OP_DELETE_ALT, NULL, section,
data, output_data, call_options);
}
int cib_client_erase(
cib_t *cib, crm_data_t **output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CIB_OP_ERASE, NULL, NULL, NULL,
output_data, call_options);
}
int cib_client_quit(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CRM_OP_QUIT, NULL, NULL, NULL, NULL, call_options);
}
int cib_client_add_notify_callback(
cib_t *cib, const char *event, void (*callback)(
const char *event, struct ha_msg *msg))
{
GList *list_item = NULL;
cib_notify_client_t *new_client = NULL;
crm_debug_2("Adding callback for %s events (%d)",
event, g_list_length(cib->notify_list));
crm_malloc0(new_client, sizeof(cib_notify_client_t));
new_client->event = event;
new_client->callback = callback;
list_item = g_list_find_custom(
cib->notify_list, new_client, ciblib_GCompareFunc);
if(list_item != NULL) {
crm_warn("Callback already present");
crm_free(new_client);
} else {
cib->notify_list = g_list_append(
cib->notify_list, new_client);
cib->cmds->register_callback(cib, event, 1);
crm_debug_3("Callback added (%d)", g_list_length(cib->notify_list));
}
return cib_ok;
}
int cib_client_del_notify_callback(
cib_t *cib, const char *event, void (*callback)(
const char *event, struct ha_msg *msg))
{
GList *list_item = NULL;
cib_notify_client_t *new_client = NULL;
crm_debug("Removing callback for %s events", event);
crm_malloc0(new_client, sizeof(cib_notify_client_t));
new_client->event = event;
new_client->callback = callback;
list_item = g_list_find_custom(
cib->notify_list, new_client, ciblib_GCompareFunc);
cib->cmds->register_callback(cib, event, 0);
if(list_item != NULL) {
cib_notify_client_t *list_client = list_item->data;
cib->notify_list =
g_list_remove(cib->notify_list, list_client);
crm_free(list_client);
crm_debug_3("Removed callback");
} else {
crm_debug_3("Callback not present");
}
crm_free(new_client);
return cib_ok;
}
gint ciblib_GCompareFunc(gconstpointer a, gconstpointer b)
{
const cib_notify_client_t *a_client = a;
const cib_notify_client_t *b_client = b;
if(a_client->callback == b_client->callback
&& safe_str_neq(a_client->event, b_client->event)) {
return 0;
} else if(((long)a_client->callback) < ((long)b_client->callback)) {
return -1;
}
return 1;
}
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*))
{
cib_callback_client_t *blob = NULL;
if(call_id < 0) {
crm_warn("CIB call failed: %s", cib_error2string(call_id));
if(only_success == FALSE) {
callback(NULL, call_id, call_id, NULL, user_data);
}
return FALSE;
}
crm_malloc0(blob, sizeof(cib_callback_client_t));
blob->only_success = only_success;
blob->user_data = user_data;
blob->callback = callback;
g_hash_table_insert(
cib_op_callback_table, GINT_TO_POINTER(call_id), blob);
return TRUE;
}
void
remove_cib_op_callback(int call_id, gboolean all_callbacks)
{
if(all_callbacks) {
if(cib_op_callback_table != NULL) {
g_hash_table_destroy(cib_op_callback_table);
}
cib_op_callback_table = g_hash_table_new_full(
g_direct_hash, g_direct_equal,
NULL, g_hash_destroy_str);
} else {
g_hash_table_remove(
cib_op_callback_table,
GINT_TO_POINTER(call_id));
}
}
int
num_cib_op_callbacks(void)
{
if(cib_op_callback_table == NULL) {
return 0;
}
return g_hash_table_size(cib_op_callback_table);
}
char *
cib_pluralSection(const char *a_section)
{
char *a_section_parent = NULL;
if (a_section == NULL) {
a_section_parent = crm_strdup("all");
} else if(strcasecmp(a_section, XML_TAG_CIB) == 0) {
a_section_parent = crm_strdup("all");
} else if(strcasecmp(a_section, XML_CIB_TAG_NODE) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_NODES);
} else if(strcasecmp(a_section, XML_CIB_TAG_STATE) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_STATUS);
} else if(strcasecmp(a_section, XML_CIB_TAG_CONSTRAINT) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS);
} else if(strcasecmp(a_section, XML_CONS_TAG_RSC_LOCATION) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS);
} else if(strcasecmp(a_section, XML_CONS_TAG_RSC_DEPEND) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS);
} else if(strcasecmp(a_section, XML_CONS_TAG_RSC_ORDER) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS);
} else if(strcasecmp(a_section, "resource") == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES);
} else if(strcasecmp(a_section, XML_CIB_TAG_RESOURCE) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES);
} else if(strcasecmp(a_section, XML_CIB_TAG_GROUP) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES);
} else if(strcasecmp(a_section, XML_CIB_TAG_INCARNATION) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES);
} else if(strcasecmp(a_section, XML_CIB_TAG_NVPAIR) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CRMCONFIG);
} else if(strcasecmp(a_section, XML_TAG_ATTR_SETS) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CRMCONFIG);
} else {
crm_err("Unknown section %s", a_section);
a_section_parent = crm_strdup("all");
}
crm_debug_2("Plural of %s is %s", crm_str(a_section), a_section_parent);
return a_section_parent;
}
const char *
cib_error2string(enum cib_errors return_code)
{
const char *error_msg = NULL;
switch(return_code) {
case cib_bad_permissions:
error_msg = "bad permissions for the on-disk configuration. shutdown heartbeat and repair.";
break;
case cib_bad_digest:
error_msg = "the on-disk configuration was manually altered. shutdown heartbeat and repair.";
break;
case cib_bad_config:
error_msg = "the on-disk configuration is not valid";
break;
case cib_msg_field_add:
error_msg = "failed adding field to cib message";
break;
case cib_id_check:
error_msg = "missing id or id-collision detected";
break;
case cib_operation:
error_msg = "invalid operation";
break;
case cib_create_msg:
error_msg = "couldnt create cib message";
break;
case cib_client_gone:
error_msg = "client left before we could send reply";
break;
case cib_not_connected:
error_msg = "not connected";
break;
case cib_not_authorized:
error_msg = "not authorized";
break;
case cib_send_failed:
error_msg = "send failed";
break;
case cib_reply_failed:
error_msg = "reply failed";
break;
case cib_return_code:
error_msg = "no return code";
break;
case cib_output_ptr:
error_msg = "nowhere to store output";
break;
case cib_output_data:
error_msg = "corrupt output data";
break;
case cib_connection:
error_msg = "connection failed";
break;
case cib_callback_register:
error_msg = "couldnt register callback channel";
break;
case cib_authentication:
error_msg = "";
break;
case cib_registration_msg:
error_msg = "invalid registration msg";
break;
case cib_callback_token:
error_msg = "callback token not found";
break;
case cib_missing:
error_msg = "cib object missing";
break;
case cib_variant:
error_msg = "unknown/corrupt cib variant";
break;
case CIBRES_MISSING_ID:
error_msg = "The id field is missing";
break;
case CIBRES_MISSING_TYPE:
error_msg = "The type field is missing";
break;
case CIBRES_MISSING_FIELD:
error_msg = "A required field is missing";
break;
case CIBRES_OBJTYPE_MISMATCH:
error_msg = "CIBRES_OBJTYPE_MISMATCH";
break;
case cib_EXISTS:
error_msg = "The object already exists";
break;
case cib_NOTEXISTS:
error_msg = "The object/attribute does not exist";
break;
case CIBRES_CORRUPT:
error_msg = "The CIB is corrupt";
break;
case cib_NOOBJECT:
error_msg = "The update was empty";
break;
case cib_NOPARENT:
error_msg = "The parent object does not exist";
break;
case cib_NODECOPY:
error_msg = "Failed while copying update";
break;
case CIBRES_OTHER:
error_msg = "CIBRES_OTHER";
break;
case cib_ok:
error_msg = "ok";
break;
case cib_unknown:
error_msg = "Unknown error";
break;
case cib_STALE:
error_msg = "Discarded old update";
break;
case cib_ACTIVATION:
error_msg = "Activation Failed";
break;
case cib_NOSECTION:
error_msg = "Required section was missing";
break;
case cib_NOTSUPPORTED:
error_msg = "Supplied information is not supported";
break;
case cib_not_master:
error_msg = "Local service is not the master instance";
break;
case cib_client_corrupt:
error_msg = "Service client not valid";
break;
case cib_remote_timeout:
error_msg = "Remote node did not respond";
break;
case cib_master_timeout:
error_msg = "No master service is currently active";
break;
case cib_revision_unsupported:
error_msg = "The required CIB revision number is not supported";
break;
case cib_revision_unknown:
error_msg = "The CIB revision number could not be determined";
break;
case cib_missing_data:
error_msg = "Required data for this CIB API call not found";
break;
case cib_no_quorum:
error_msg = "Write requires quorum";
break;
case cib_diff_failed:
error_msg = "Application of an update diff failed";
break;
case cib_diff_resync:
error_msg = "Application of an update diff failed, requesting a full refresh";
break;
case cib_bad_section:
error_msg = "Invalid CIB section specified";
break;
case cib_old_data:
error_msg = "Update was older than existing configuration";
break;
case cib_dtd_validation:
- error_msg = "Update does not conform to the DTD in "HA_NOARCHDATAHBDIR"/crm.dtd";
+ error_msg = "Update does not conform to the DTD in "DTD_DIRECTORY"/crm.dtd";
break;
case cib_invalid_argument:
error_msg = "Invalid argument";
break;
}
if(error_msg == NULL) {
crm_err("Unknown CIB Error Code: %d", return_code);
error_msg = "<unknown error>";
}
return error_msg;
}
const char *
cib_op2string(enum cib_update_op operation)
{
const char *operation_msg = NULL;
switch(operation) {
case 0:
operation_msg = "none";
break;
case 1:
operation_msg = "add";
break;
case 2:
operation_msg = "modify";
break;
case 3:
operation_msg = "delete";
break;
case CIB_UPDATE_OP_MAX:
operation_msg = "invalid operation";
break;
}
if(operation_msg == NULL) {
crm_err("Unknown CIB operation %d", operation);
operation_msg = "<unknown operation>";
}
return operation_msg;
}
int
cib_section2enum(const char *a_section)
{
if(a_section == NULL || strcasecmp(a_section, "all") == 0) {
return cib_section_all;
} else if(strcasecmp(a_section, XML_CIB_TAG_NODES) == 0) {
return cib_section_nodes;
} else if(strcasecmp(a_section, XML_CIB_TAG_STATUS) == 0) {
return cib_section_status;
} else if(strcasecmp(a_section, XML_CIB_TAG_CONSTRAINTS) == 0) {
return cib_section_constraints;
} else if(strcasecmp(a_section, XML_CIB_TAG_RESOURCES) == 0) {
return cib_section_resources;
} else if(strcasecmp(a_section, XML_CIB_TAG_CRMCONFIG) == 0) {
return cib_section_crmconfig;
}
crm_err("Unknown CIB section: %s", a_section);
return cib_section_none;
}
int
cib_compare_generation(crm_data_t *left, crm_data_t *right)
{
int lpc = 0;
const char *attributes[] = {
XML_ATTR_GENERATION_ADMIN,
XML_ATTR_GENERATION,
XML_ATTR_NUMUPDATES,
XML_ATTR_NUMPEERS
};
crm_log_xml_debug_3(left, "left");
crm_log_xml_debug_3(right, "right");
for(lpc = 0; lpc < DIMOF(attributes); lpc++) {
int int_elem_l = -1;
int int_elem_r = -1;
const char *elem_r = NULL;
const char *elem_l = crm_element_value(left, attributes[lpc]);
if(right != NULL) {
elem_r = crm_element_value(right, attributes[lpc]);
}
if(elem_l != NULL) { int_elem_l = crm_parse_int(elem_l, NULL); }
if(elem_r != NULL) { int_elem_r = crm_parse_int(elem_r, NULL); }
if(int_elem_l < int_elem_r) {
crm_debug_2("%s (%s < %s)", attributes[lpc],
crm_str(elem_l), crm_str(elem_r));
return -1;
} else if(int_elem_l > int_elem_r) {
crm_debug_2("%s (%s > %s)", attributes[lpc],
crm_str(elem_l), crm_str(elem_r));
return 1;
}
}
return 0;
}
crm_data_t*
get_cib_copy(cib_t *cib)
{
crm_data_t *xml_cib;
#if CRM_DEPRECATED_SINCE_2_0_4
crm_data_t *xml_cib_copy;
#endif
int options = cib_scope_local|cib_sync_call;
if(cib->cmds->query(cib, NULL, &xml_cib, options) != cib_ok) {
crm_err("Couldnt retrieve the CIB");
return NULL;
} else if(xml_cib == NULL) {
crm_err("The CIB result was empty");
return NULL;
}
if(safe_str_eq(crm_element_name(xml_cib), XML_TAG_CIB)) {
return xml_cib;
#if CRM_DEPRECATED_SINCE_2_0_4
} else {
xml_cib_copy = copy_xml(
find_xml_node(xml_cib, XML_TAG_CIB, TRUE));
free_xml(xml_cib);
return xml_cib_copy;
#endif
}
free_xml(xml_cib);
return NULL;
}
crm_data_t*
cib_get_generation(cib_t *cib)
{
crm_data_t *the_cib = get_cib_copy(cib);
crm_data_t *generation = create_xml_node(
NULL, XML_CIB_TAG_GENERATION_TUPPLE);
if(the_cib != NULL) {
copy_in_properties(generation, the_cib);
free_xml(the_cib);
}
return generation;
}
gboolean
apply_cib_diff(crm_data_t *old, crm_data_t *diff, crm_data_t **new)
{
gboolean result = TRUE;
const char *value = NULL;
int this_updates = 0;
int this_epoch = 0;
int this_admin_epoch = 0;
int diff_add_updates = 0;
int diff_add_epoch = 0;
int diff_add_admin_epoch = 0;
int diff_del_updates = 0;
int diff_del_epoch = 0;
int diff_del_admin_epoch = 0;
CRM_CHECK(diff != NULL, return FALSE);
CRM_CHECK(old != NULL, return FALSE);
value = crm_element_value(old, XML_ATTR_GENERATION_ADMIN);
this_admin_epoch = crm_parse_int(value, "0");
crm_debug_3("%s=%d (%s)", XML_ATTR_GENERATION_ADMIN,
this_admin_epoch, value);
value = crm_element_value(old, XML_ATTR_GENERATION);
this_epoch = crm_parse_int(value, "0");
crm_debug_3("%s=%d (%s)", XML_ATTR_GENERATION, this_epoch, value);
value = crm_element_value(old, XML_ATTR_NUMUPDATES);
this_updates = crm_parse_int(value, "0");
crm_debug_3("%s=%d (%s)", XML_ATTR_NUMUPDATES, this_updates, value);
cib_diff_version_details(
diff,
&diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
&diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
value = NULL;
if(result && diff_del_admin_epoch != this_admin_epoch) {
value = XML_ATTR_GENERATION_ADMIN;
result = FALSE;
crm_debug_3("%s=%d", value, diff_del_admin_epoch);
} else if(result && diff_del_epoch != this_epoch) {
value = XML_ATTR_GENERATION;
result = FALSE;
crm_debug_3("%s=%d", value, diff_del_epoch);
} else if(result && diff_del_updates != this_updates) {
value = XML_ATTR_NUMUPDATES;
result = FALSE;
crm_debug_3("%s=%d", value, diff_del_updates);
}
if(result) {
int len = 0;
crm_data_t *tmp = NULL;
crm_data_t *diff_copy = copy_xml(diff);
tmp = find_xml_node(diff_copy, "diff-removed", TRUE);
if(tmp != NULL) {
len = tmp->nfields;
cl_msg_remove(tmp, XML_ATTR_GENERATION_ADMIN);
cl_msg_remove(tmp, XML_ATTR_GENERATION);
cl_msg_remove(tmp, XML_ATTR_NUMUPDATES);
}
tmp = find_xml_node(diff_copy, "diff-added", TRUE);
if(tmp != NULL) {
len = tmp->nfields;
cl_msg_remove(tmp, XML_ATTR_GENERATION_ADMIN);
cl_msg_remove(tmp, XML_ATTR_GENERATION);
cl_msg_remove(tmp, XML_ATTR_NUMUPDATES);
}
result = apply_xml_diff(old, diff_copy, new);
free_xml(diff_copy);
} else {
crm_err("target and diff %s values didnt match", value);
}
return result;
}
gboolean xml_has_child(crm_data_t *data, const char *name);
gboolean
xml_has_child(crm_data_t *data, const char *name)
{
xml_child_iter_filter(data, child, name,
return TRUE;
);
return FALSE;
}
gboolean
cib_config_changed(crm_data_t *old_cib, crm_data_t *new_cib, crm_data_t **result)
{
gboolean config_changes = FALSE;
const char *tag = NULL;
crm_data_t *diff = NULL;
crm_data_t *dest = NULL;
if(result) {
*result = NULL;
}
diff = diff_xml_object(old_cib, new_cib, FALSE);
if(diff == NULL) {
return FALSE;
}
tag = "diff-removed";
dest = find_xml_node(diff, tag, FALSE);
if(dest) {
dest = find_xml_node(dest, "cib", FALSE);
}
if(dest) {
if(xml_has_child(dest, "status")) {
cl_msg_remove(dest, "status");
}
if(xml_has_children(dest)) {
config_changes = TRUE;
}
}
tag = "diff-added";
dest = find_xml_node(diff, tag, FALSE);
if(dest) {
dest = find_xml_node(dest, "cib", FALSE);
}
if(dest) {
if(xml_has_child(dest, "status")) {
cl_msg_remove(dest, "status");
}
if(xml_has_children(dest)) {
config_changes = TRUE;
}
}
/* TODO: Check cib attributes */
if(result) {
*result = diff;
} else {
free_xml(diff);
}
return config_changes;
}
crm_data_t *
diff_cib_object(crm_data_t *old_cib, crm_data_t *new_cib, gboolean suppress)
{
crm_data_t *dest = NULL;
crm_data_t *src = NULL;
const char *name = NULL;
const char *value = NULL;
crm_data_t *diff = diff_xml_object(old_cib, new_cib, suppress);
/* add complete version information */
src = old_cib;
dest = find_xml_node(diff, "diff-removed", FALSE);
if(src != NULL && dest != NULL) {
name = XML_ATTR_GENERATION_ADMIN;
value = crm_element_value(src, name);
if(value == NULL) {
value = "0";
}
crm_xml_add(dest, name, value);
name = XML_ATTR_GENERATION;
value = crm_element_value(src, name);
if(value == NULL) {
value = "0";
}
crm_xml_add(dest, name, value);
name = XML_ATTR_NUMUPDATES;
value = crm_element_value(src, name);
if(value == NULL) {
value = "0";
}
crm_xml_add(dest, name, value);
}
src = new_cib;
dest = find_xml_node(diff, "diff-added", FALSE);
if(src != NULL && dest != NULL) {
name = XML_ATTR_GENERATION_ADMIN;
value = crm_element_value(src, name);
if(value == NULL) {
value = "0";
}
crm_xml_add(dest, name, value);
name = XML_ATTR_GENERATION;
value = crm_element_value(src, name);
if(value == NULL) {
value = "0";
}
crm_xml_add(dest, name, value);
name = XML_ATTR_NUMUPDATES;
value = crm_element_value(src, name);
if(value == NULL) {
value = "0";
}
crm_xml_add(dest, name, value);
}
return diff;
}
void
log_cib_diff(int log_level, crm_data_t *diff, const char *function)
{
int add_updates = 0;
int add_epoch = 0;
int add_admin_epoch = 0;
int del_updates = 0;
int del_epoch = 0;
int del_admin_epoch = 0;
if(diff == NULL) {
return;
}
cib_diff_version_details(
diff, &add_admin_epoch, &add_epoch, &add_updates,
&del_admin_epoch, &del_epoch, &del_updates);
if(add_updates != del_updates) {
do_crm_log(log_level, "%s: Diff: --- %d.%d.%d", function,
del_admin_epoch, del_epoch, del_updates);
do_crm_log(log_level, "%s: Diff: +++ %d.%d.%d", function,
add_admin_epoch, add_epoch, add_updates);
} else if(diff != NULL) {
do_crm_log(log_level,
"%s: Local-only Change: %d.%d.%d", function,
add_admin_epoch, add_epoch, add_updates);
}
log_xml_diff(log_level, diff, function);
}
gboolean
cib_version_details(
crm_data_t *cib, int *admin_epoch, int *epoch, int *updates)
{
const char *value = NULL;
if(cib == NULL) {
*admin_epoch = -1;
*epoch = -1;
*updates = -1;
return FALSE;
} else {
value = crm_element_value(cib, XML_ATTR_GENERATION_ADMIN);
*admin_epoch = crm_parse_int(value, "-1");
value = crm_element_value(cib, XML_ATTR_GENERATION);
*epoch = crm_parse_int(value, "-1");
value = crm_element_value(cib, XML_ATTR_NUMUPDATES);
*updates = crm_parse_int(value, "-1");
}
return TRUE;
}
gboolean
cib_diff_version_details(
crm_data_t *diff, int *admin_epoch, int *epoch, int *updates,
int *_admin_epoch, int *_epoch, int *_updates)
{
crm_data_t *tmp = NULL;
tmp = find_xml_node(diff, "diff-added", FALSE);
cib_version_details(tmp, admin_epoch, epoch, updates);
tmp = find_xml_node(diff, "diff-removed", FALSE);
cib_version_details(tmp, _admin_epoch, _epoch, _updates);
return TRUE;
}
/*
* The caller should never free the return value
*/
crm_data_t*
get_object_root(const char *object_type, crm_data_t *the_root)
{
const char *node_stack[2];
crm_data_t *tmp_node = NULL;
if(the_root == NULL) {
crm_err("CIB root object was NULL");
return NULL;
}
node_stack[0] = XML_CIB_TAG_CONFIGURATION;
node_stack[1] = object_type;
if(object_type == NULL
|| strlen(object_type) == 0
|| safe_str_eq(XML_CIB_TAG_SECTION_ALL, object_type)
|| safe_str_eq(XML_TAG_CIB, object_type)) {
/* get the whole cib */
return the_root;
} else if(strcasecmp(object_type, XML_CIB_TAG_STATUS) == 0) {
/* these live in a different place */
tmp_node = find_xml_node(the_root, XML_CIB_TAG_STATUS, FALSE);
node_stack[0] = object_type;
node_stack[1] = NULL;
} else {
tmp_node = find_xml_node_nested(the_root, node_stack, 2);
}
if (tmp_node == NULL) {
crm_debug_2("Section [%s [%s]] not present in %s",
node_stack[0],
node_stack[1]?node_stack[1]:"",
crm_element_name(the_root));
}
return tmp_node;
}
const char *
get_crm_option(crm_data_t *cib, const char *name, gboolean do_warn)
{
const char * value = NULL;
crm_data_t * a_default = NULL;
crm_data_t * config = get_object_root(XML_CIB_TAG_CRMCONFIG, cib);
if(config != NULL) {
a_default = find_entity(config, XML_CIB_TAG_NVPAIR, name);
}
if(a_default == NULL) {
if(do_warn) {
crm_warn("Option %s not set", name);
}
return NULL;
}
value = crm_element_value(a_default, XML_NVPAIR_ATTR_VALUE);
if(safe_str_eq(value, "")) {
value = NULL;
}
return value;
}
crm_data_t*
create_cib_fragment_adv(
crm_data_t *update, const char *update_section, const char *source)
{
crm_data_t *cib = NULL;
gboolean whole_cib = FALSE;
crm_data_t *object_root = NULL;
const char *update_name = NULL;
char *local_section = NULL;
/* crm_debug("Creating a blank fragment: %s", update_section); */
if(update == NULL && update_section == NULL) {
crm_debug_3("Creating a blank fragment");
update = createEmptyCib();
crm_xml_add(cib, XML_ATTR_ORIGIN, source);
return update;
} else if(update == NULL) {
crm_err("No update to create a fragment for");
return NULL;
} else if(update_section == NULL) {
local_section = cib_pluralSection(update_name);
update_section = local_section;
}
if(safe_str_eq(crm_element_name(update), XML_TAG_CIB)) {
whole_cib = TRUE;
}
if(whole_cib == FALSE) {
cib = createEmptyCib();
crm_xml_add(cib, XML_ATTR_ORIGIN, source);
object_root = get_object_root(update_section, cib);
add_node_copy(object_root, update);
} else {
cib = copy_xml(update);
crm_xml_add(cib, XML_ATTR_ORIGIN, source);
}
crm_free(local_section);
crm_debug_3("Verifying created fragment");
if(verifyCibXml(cib) == FALSE) {
crm_err("Fragment creation failed");
crm_log_xml_err(cib, "[src]");
free_xml(cib);
cib = NULL;
}
return cib;
}
/*
* It is the callers responsibility to free both the new CIB (output)
* and the new CIB (input)
*/
crm_data_t*
createEmptyCib(void)
{
crm_data_t *cib_root = NULL, *config = NULL, *status = NULL;
cib_root = create_xml_node(NULL, XML_TAG_CIB);
config = create_xml_node(cib_root, XML_CIB_TAG_CONFIGURATION);
status = create_xml_node(cib_root, XML_CIB_TAG_STATUS);
/* crm_xml_add(cib_root, "version", "1"); */
crm_xml_add(cib_root, "generated", XML_BOOLEAN_TRUE);
create_xml_node(config, XML_CIB_TAG_CRMCONFIG);
create_xml_node(config, XML_CIB_TAG_NODES);
create_xml_node(config, XML_CIB_TAG_RESOURCES);
create_xml_node(config, XML_CIB_TAG_CONSTRAINTS);
if (verifyCibXml(cib_root)) {
return cib_root;
}
free_xml(cib_root);
crm_crit("The generated CIB did not pass integrity testing!!"
" All hope is lost.");
return NULL;
}
gboolean
verifyCibXml(crm_data_t *cib)
{
int lpc = 0;
gboolean is_valid = TRUE;
crm_data_t *tmp_node = NULL;
const char *sections[] = {
XML_CIB_TAG_NODES,
XML_CIB_TAG_RESOURCES,
XML_CIB_TAG_CONSTRAINTS,
XML_CIB_TAG_STATUS,
XML_CIB_TAG_CRMCONFIG
};
if (cib == NULL) {
crm_warn("CIB was empty.");
return FALSE;
}
/* basic tests... are the standard section all there */
for(lpc = 0; lpc < DIMOF(sections); lpc++) {
tmp_node = get_object_root(sections[lpc], cib);
if (tmp_node == NULL) {
crm_warn("Section %s is not present in the CIB",
sections[lpc]);
is_valid = FALSE;
}
}
/* more integrity tests */
return is_valid;
}
gboolean verify_cib_cmds(cib_t *cib)
{
gboolean valid = TRUE;
if(cib->cmds->variant_op == NULL) {
crm_err("Operation variant_op not set");
valid = FALSE;
}
if(cib->cmds->signon == NULL) {
crm_err("Operation signon not set");
valid = FALSE;
}
if(cib->cmds->signoff == NULL) {
crm_err("Operation signoff not set");
valid = FALSE;
}
if(cib->cmds->free == NULL) {
crm_err("Operation free not set");
valid = FALSE;
}
if(cib->cmds->set_op_callback == NULL) {
crm_err("Operation set_op_callback not set");
valid = FALSE;
}
if(cib->cmds->add_notify_callback == NULL) {
crm_err("Operation add_notify_callback not set");
valid = FALSE;
}
if(cib->cmds->del_notify_callback == NULL) {
crm_err("Operation del_notify_callback not set");
valid = FALSE;
}
if(cib->cmds->set_connection_dnotify == NULL) {
crm_err("Operation set_connection_dnotify not set");
valid = FALSE;
}
if(cib->cmds->channel == NULL) {
crm_err("Operation channel not set");
valid = FALSE;
}
if(cib->cmds->inputfd == NULL) {
crm_err("Operation inputfd not set");
valid = FALSE;
}
if(cib->cmds->noop == NULL) {
crm_err("Operation noop not set");
valid = FALSE;
}
if(cib->cmds->ping == NULL) {
crm_err("Operation ping not set");
valid = FALSE;
}
if(cib->cmds->query == NULL) {
crm_err("Operation query not set");
valid = FALSE;
}
if(cib->cmds->query_from == NULL) {
crm_err("Operation query_from not set");
valid = FALSE;
}
if(cib->cmds->is_master == NULL) {
crm_err("Operation is_master not set");
valid = FALSE;
}
if(cib->cmds->set_master == NULL) {
crm_err("Operation set_master not set");
valid = FALSE;
}
if(cib->cmds->set_slave == NULL) {
crm_err("Operation set_slave not set");
valid = FALSE;
}
if(cib->cmds->set_slave_all == NULL) {
crm_err("Operation set_slave_all not set");
valid = FALSE;
}
if(cib->cmds->sync == NULL) {
crm_err("Operation sync not set");
valid = FALSE;
} if(cib->cmds->sync_from == NULL) {
crm_err("Operation sync_from not set");
valid = FALSE;
}
if(cib->cmds->bump_epoch == NULL) {
crm_err("Operation bump_epoch not set");
valid = FALSE;
}
if(cib->cmds->create == NULL) {
crm_err("Operation create not set");
valid = FALSE;
}
if(cib->cmds->modify == NULL) {
crm_err("Operation modify not set");
valid = FALSE;
}
if(cib->cmds->replace == NULL) {
crm_err("Operation replace not set");
valid = FALSE;
}
if(cib->cmds->delete == NULL) {
crm_err("Operation delete not set");
valid = FALSE;
}
if(cib->cmds->erase == NULL) {
crm_err("Operation erase not set");
valid = FALSE;
}
if(cib->cmds->quit == NULL) {
crm_err("Operation quit not set");
valid = FALSE;
}
if(cib->cmds->msgready == NULL) {
crm_err("Operation msgready not set");
valid = FALSE;
}
if(cib->cmds->rcvmsg == NULL) {
crm_err("Operation rcvmsg not set");
valid = FALSE;
}
if(cib->cmds->dispatch == NULL) {
crm_err("Operation dispatch not set");
valid = FALSE;
}
return valid;
}
diff --git a/pengine/ptest.c b/pengine/ptest.c
index 17193a44fe..96a2fbcee7 100644
--- a/pengine/ptest.c
+++ b/pengine/ptest.c
@@ -1,500 +1,500 @@
/*
* 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 <crm/crm.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <crm/transition.h>
#include <crm/common/xml.h>
#include <crm/common/util.h>
#include <crm/msg_xml.h>
#include <crm/cib.h>
#define OPTARGS "V?X:D:G:I:Lwxd:aS"
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
#include <glib.h>
#include <pengine.h>
#include <lib/crm/pengine/utils.h>
#include <allocate.h>
#if HAVE_LIBXML2
# include <libxml/parser.h>
#endif
gboolean use_stdin = FALSE;
gboolean do_simulation = FALSE;
gboolean inhibit_exit = FALSE;
gboolean all_actions = FALSE;
extern crm_data_t * do_calculations(
pe_working_set_t *data_set, crm_data_t *xml_input, ha_time_t *now);
extern void cleanup_calculations(pe_working_set_t *data_set);
char *use_date = NULL;
FILE *dot_strm = NULL;
#define DOT_PREFIX "PE_DOT: "
/* #define DOT_PREFIX "" */
#define dot_write(fmt...) if(dot_strm != NULL) { \
fprintf(dot_strm, fmt); \
fprintf(dot_strm, "\n"); \
} else { \
crm_debug(DOT_PREFIX""fmt); \
}
static void
init_dotfile(void)
{
dot_write(" digraph \"g\" {");
/* dot_write(" size = \"30,30\""); */
/* dot_write(" graph ["); */
/* dot_write(" fontsize = \"12\""); */
/* dot_write(" fontname = \"Times-Roman\""); */
/* dot_write(" fontcolor = \"black\""); */
/* dot_write(" bb = \"0,0,398.922306,478.927856\""); */
/* dot_write(" color = \"black\""); */
/* dot_write(" ]"); */
/* dot_write(" node ["); */
/* dot_write(" fontsize = \"12\""); */
/* dot_write(" fontname = \"Times-Roman\""); */
/* dot_write(" fontcolor = \"black\""); */
/* dot_write(" shape = \"ellipse\""); */
/* dot_write(" color = \"black\""); */
/* dot_write(" ]"); */
/* dot_write(" edge ["); */
/* dot_write(" fontsize = \"12\""); */
/* dot_write(" fontname = \"Times-Roman\""); */
/* dot_write(" fontcolor = \"black\""); */
/* dot_write(" color = \"black\""); */
/* dot_write(" ]"); */
}
static void
usage(const char *cli, int exitcode)
{
FILE *out = exitcode?stderr:stdout;
fprintf(out, "Usage: %s -(?|L|X|x) [-V] [-D] [-G] [-I]\n", cli);
fprintf(out, " --%s (-%c): This text\n\n", "help", '?');
fprintf(out, " --%s (-%c): Increase verbosity (can be supplied multiple times)\n\n", "verbose", 'V');
fprintf(out, " --%s (-%c): Connect to the CIB and use the current contents as input\n", "live-check", 'L');
fprintf(out, " --%s (-%c): Look for xml on stdin\n", "xml-stream", 'x');
fprintf(out, " --%s (-%c)\t<filename> : Look for xml in the named file\n\n", "xml-file", 'X');
fprintf(out, " --%s (-%c)\t<filename> : Save the transition graph to the named file\n", "save-graph", 'G');
fprintf(out, " --%s (-%c)\t<filename> : Save the DOT formatted transition graph to the named file\n", "save-dotfile", 'D');
fprintf(out, " --%s (-%c)\t<filename> : Save the input to the named file\n", "save-input", 'I');
exit(exitcode);
}
static char *
create_action_name(action_t *action)
{
char *action_name = NULL;
const char *action_host = NULL;
if(action->node) {
action_host = action->node->details->uname;
action_name = crm_concat(action->uuid, action_host, ' ');
} else if(action->pseudo) {
action_name = crm_strdup(action->uuid);
} else {
action_host = "<none>";
action_name = crm_concat(action->uuid, action_host, ' ');
}
return action_name;
}
gboolean USE_LIVE_CIB = FALSE;
int
main(int argc, char **argv)
{
gboolean all_good = TRUE;
enum transition_status graph_rc = -1;
crm_graph_t *transition = NULL;
ha_time_t *a_date = NULL;
cib_t * cib_conn = NULL;
crm_data_t * cib_object = NULL;
int argerr = 0;
int flag;
char *msg_buffer = NULL;
gboolean optional = FALSE;
pe_working_set_t data_set;
const char *source = NULL;
const char *xml_file = NULL;
const char *dot_file = NULL;
const char *graph_file = NULL;
const char *input_file = NULL;
cl_log_set_entity("ptest");
cl_log_set_facility(LOG_USER);
set_crm_log_level(LOG_CRIT-1);
while (1) {
#ifdef HAVE_GETOPT_H
int option_index = 0;
static struct option long_options[] = {
/* Top-level Options */
{"help", 0, 0, '?'},
{"verbose", 0, 0, 'V'},
{"live-check", 0, 0, 'L'},
{"xml-stream", 0, 0, 'x'},
{"xml-file", 1, 0, 'X'},
{"simulate", 0, 0, 'S'},
{"save-graph", 1, 0, 'G'},
{"save-dotfile",1, 0, 'D'},
{"save-input", 1, 0, 'I'},
{0, 0, 0, 0}
};
#endif
#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) {
#ifdef HAVE_GETOPT_H
case 0:
printf("option %s", long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
break;
#endif
case 'S':
do_simulation = TRUE;
break;
case 'a':
all_actions = TRUE;
break;
case 'w':
inhibit_exit = TRUE;
break;
case 'x':
use_stdin = TRUE;
break;
case 'X':
xml_file = optarg;
break;
case 'd':
use_date = optarg;
break;
case 'D':
dot_file = optarg;
break;
case 'G':
graph_file = optarg;
break;
case 'I':
input_file = optarg;
break;
case 'V':
cl_log_enable_stderr(TRUE);
alter_debug(DEBUG_INC);
break;
case 'L':
USE_LIVE_CIB = TRUE;
break;
case '?':
usage("ptest", 0);
break;
default:
printf("?? getopt returned character code 0%o ??\n", flag);
++argerr;
break;
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc) {
printf("%s ", argv[optind++]);
}
printf("\n");
}
if (optind > argc) {
++argerr;
}
if (argerr) {
crm_err("%d errors in option parsing", argerr);
usage("ptest", 1);
}
crm_info("=#=#=#=#= Getting XML =#=#=#=#=");
if(USE_LIVE_CIB) {
int rc = cib_ok;
source = "live cib";
cib_conn = cib_new();
rc = cib_conn->cmds->signon(
cib_conn, "ptest", cib_command_synchronous);
if(rc == cib_ok) {
crm_info("Reading XML from: live cluster");
cib_object = get_cib_copy(cib_conn);
} else {
fprintf(stderr, "Live CIB query failed: %s\n",
cib_error2string(rc));
return 3;
}
if(cib_object == NULL) {
fprintf(stderr, "Live CIB query failed: empty result\n");
return 3;
}
} else if(xml_file != NULL) {
FILE *xml_strm = fopen(xml_file, "r");
source = xml_file;
if(xml_strm == NULL) {
cl_perror("Could not open %s for reading", xml_file);
} else {
if(strstr(xml_file, ".bz2") != NULL) {
cib_object = file2xml(xml_strm, TRUE);
} else {
cib_object = file2xml(xml_strm, FALSE);
}
fclose(xml_strm);
}
} else if(use_stdin) {
source = "stdin";
cib_object = stdin2xml();
}
if(cib_object == NULL && source) {
fprintf(stderr, "Could not parse configuration input from: %s\n", source);
return 4;
} else if(cib_object == NULL) {
fprintf(stderr, "Not configuration specified\n");
usage("ptest", 1);
}
crm_notice("Required feature set: %s", feature_set(cib_object));
do_id_check(cib_object, NULL, FALSE, FALSE);
- if(!validate_with_dtd(cib_object,FALSE,HA_NOARCHDATAHBDIR"/crm.dtd")) {
+ if(!validate_with_dtd(cib_object,FALSE,DTD_DIRECTORY"/crm.dtd")) {
crm_crit("%s does not contain a valid configuration", xml_file?xml_file:"<stdin>");
all_good = FALSE;
}
if(input_file != NULL) {
FILE *input_strm = fopen(input_file, "w");
if(input_strm == NULL) {
cl_perror("Could not open %s for writing", input_file);
} else {
msg_buffer = dump_xml_formatted(cib_object);
if(fprintf(input_strm, "%s\n", msg_buffer) < 0) {
cl_perror("Write to %s failed", input_file);
}
fflush(input_strm);
fclose(input_strm);
crm_free(msg_buffer);
}
}
if(use_date != NULL) {
a_date = parse_date(&use_date);
log_date(LOG_WARNING, "Set fake 'now' to",
a_date, ha_log_date|ha_log_time);
log_date(LOG_WARNING, "Set fake 'now' to (localtime)",
a_date, ha_log_date|ha_log_time|ha_log_local);
}
do_calculations(&data_set, cib_object, a_date);
msg_buffer = dump_xml_formatted(data_set.graph);
if(safe_str_eq(graph_file, "-")) {
fprintf(stdout, "%s\n", msg_buffer);
fflush(stdout);
} else if(graph_file != NULL) {
FILE *graph_strm = fopen(graph_file, "w");
if(graph_strm == NULL) {
cl_perror("Could not open %s for writing", graph_file);
} else {
if(fprintf(graph_strm, "%s\n", msg_buffer) < 0) {
cl_perror("Write to %s failed", graph_file);
}
fflush(graph_strm);
fclose(graph_strm);
}
}
crm_free(msg_buffer);
if(dot_file != NULL) {
dot_strm = fopen(dot_file, "w");
if(dot_strm == NULL) {
cl_perror("Could not open %s for writing", dot_file);
}
}
if(dot_strm == NULL) {
goto simulate;
}
init_dotfile();
slist_iter(
action, action_t, data_set.actions, lpc,
const char *style = "filled";
const char *font = "black";
const char *color = "black";
const char *fill = NULL;
char *action_name = create_action_name(action);
crm_debug_3("Action %d: %p", action->id, action);
if(action->pseudo) {
font = "orange";
}
style = "dashed";
if(action->dumped) {
style = "bold";
color = "green";
} else if(action->rsc != NULL
&& is_not_set(action->rsc->flags, pe_rsc_managed)) {
color = "purple";
if(all_actions == FALSE) {
goto dont_write;
}
} else if(action->optional) {
color = "blue";
if(all_actions == FALSE) {
goto dont_write;
}
} else {
color = "red";
CRM_CHECK(action->runnable == FALSE, ;);
}
action->dumped = TRUE;
dot_write("\"%s\" [ style=%s color=\"%s\" fontcolor=\"%s\" %s%s]",
action_name, style, color, font, fill?"fillcolor=":"", fill?fill:"");
dont_write:
crm_free(action_name);
);
slist_iter(
action, action_t, data_set.actions, lpc,
slist_iter(
before, action_wrapper_t, action->actions_before, lpc2,
char *before_name = NULL;
char *after_name = NULL;
const char *style = "dashed";
optional = TRUE;
if(before->state == pe_link_dumped) {
optional = FALSE;
style = "bold";
} else if(action->pseudo
&& (before->type & pe_order_stonith_stop)) {
continue;
} else if(before->state == pe_link_dup) {
continue;
} else if(action->dumped && before->action->dumped) {
optional = FALSE;
}
if(all_actions || optional == FALSE) {
before_name = create_action_name(before->action);
after_name = create_action_name(action);
dot_write("\"%s\" -> \"%s\" [ style = %s]",
before_name, after_name, style);
crm_free(before_name);
crm_free(after_name);
}
);
);
dot_write("}");
if(dot_strm != NULL) {
fflush(dot_strm);
fclose(dot_strm);
}
simulate:
if(do_simulation == FALSE) {
goto cleanup;
}
transition = unpack_graph(data_set.graph);
transition->batch_limit = 0;
print_graph(LOG_DEBUG, transition);
do {
graph_rc = run_graph(transition);
} while(graph_rc == transition_active);
if(graph_rc != transition_complete) {
crm_crit("Transition failed: %s", transition_status(graph_rc));
print_graph(LOG_ERR, transition);
}
destroy_graph(transition);
CRM_CHECK(graph_rc == transition_complete, all_good = FALSE; crm_err("An invalid transition was produced"));
cleanup:
cleanup_alloc_calculations(&data_set);
#if HAVE_LIBXML2
xmlCleanupParser();
#endif
/* required for MallocDebug.app */
if(inhibit_exit) {
GMainLoop* mainloop = g_main_new(FALSE);
g_main_run(mainloop);
}
if(all_good) {
return 0;
}
return 5;
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jul 8, 6:28 PM (7 h, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2002652
Default Alt Text
(113 KB)

Event Timeline