diff --git a/.gitignore b/.gitignore index 775b07e193b..1b75d1e2c4b 100644 --- a/.gitignore +++ b/.gitignore @@ -138,7 +138,6 @@ publican.cfg /doc/HTML /doc/abi_dumps /doc/abi-check -/doc/acls.html /doc/api/* /doc/compat_reports /doc/crm_fencing.html @@ -213,6 +212,7 @@ pacemaker-[a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9] /cts/HBDummy /doc/Clusters_from_Scratch.txt /doc/Pacemaker_Explained.txt +/doc/acls.html /fencing /lrmd /mcp diff --git a/configure.ac b/configure.ac index 58d39cdc0c2..407330956ad 100644 --- a/configure.ac +++ b/configure.ac @@ -1885,8 +1885,6 @@ CFLAGS_COPY="$CFLAGS" AC_SUBST(CFLAGS_COPY) AC_SUBST(LIBADD_DL) dnl extra flags for dynamic linking libraries -AC_SUBST(LIBADD_INTL) dnl extra flags for GNU gettext stuff... - AC_SUBST(LOCALE) dnl Options for cleaning up the compiler output diff --git a/daemons/controld/controld_execd.c b/daemons/controld/controld_execd.c index 0f9d8026e70..9e8dd36ea9d 100644 --- a/daemons/controld/controld_execd.c +++ b/daemons/controld/controld_execd.c @@ -762,9 +762,7 @@ is_rsc_active(lrm_state_t * lrm_state, const char *rsc_id) } else if (entry->last->rc == PCMK_OCF_OK && safe_str_eq(entry->last->op_type, CRMD_ACTION_MIGRATE)) { - /* a stricter check is too complex... - * leave that to the PE - */ + // A stricter check is too complex ... leave that to the scheduler return FALSE; } else if (entry->last->rc == PCMK_OCF_NOT_RUNNING) { diff --git a/daemons/controld/controld_fencing.c b/daemons/controld/controld_fencing.c index 0933487b76b..d9b1e1ecf74 100644 --- a/daemons/controld/controld_fencing.c +++ b/daemons/controld/controld_fencing.c @@ -530,7 +530,7 @@ tengine_stonith_notify(stonith_t *st, stonith_event_t *st_event) * Unfortunately, the controller doesn't have a simple, reliable way * to map hosts to guests. It might be possible to track this in the * peer cache via crm_remote_peer_cache_refresh(). For now, we rely - * on the PE creating fence pseudo-events for the guests. + * on the scheduler creating fence pseudo-events for the guests. */ if (st_event->client_origin diff --git a/daemons/controld/controld_fsa.c b/daemons/controld/controld_fsa.c index 190246297e1..6760224eab4 100644 --- a/daemons/controld/controld_fsa.c +++ b/daemons/controld/controld_fsa.c @@ -397,7 +397,7 @@ s_crmd_fsa_actions(fsa_data_t * fsa_data) /* * Low(er) priority actions * Make sure the CIB is always updated before invoking the - * PE, and the PE before the TE + * scheduler, and the scheduler before the transition engine. */ } else if (fsa_actions & A_TE_HALT) { do_fsa_action(fsa_data, A_TE_HALT, do_te_invoke); diff --git a/daemons/controld/controld_join_dc.c b/daemons/controld/controld_join_dc.c index d13a84258bd..988aaa690be 100644 --- a/daemons/controld/controld_join_dc.c +++ b/daemons/controld/controld_join_dc.c @@ -261,8 +261,8 @@ do_dc_join_offer_one(long long action, join_make_offer(NULL, member, NULL); } - /* this was a genuine join request, cancel any existing - * transition and invoke the PE + /* This was a genuine join request; cancel any existing transition and + * invoke the scheduler. */ abort_transition(INFINITY, tg_restart, "Node join", NULL); diff --git a/daemons/controld/controld_schedulerd.c b/daemons/controld/controld_schedulerd.c index 4b76355c8d0..e19102bb1ec 100644 --- a/daemons/controld/controld_schedulerd.c +++ b/daemons/controld/controld_schedulerd.c @@ -164,7 +164,7 @@ pe_subsystem_new() /*! * \internal - * \brief Send an XML message to the PE + * \brief Send an XML message to the scheduler * * \param[in] cmd XML message to send * diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c index 9d3f9246bbd..ea369100427 100644 --- a/daemons/fenced/fenced_commands.c +++ b/daemons/fenced/fenced_commands.c @@ -1962,7 +1962,7 @@ stonith_query(xmlNode * msg, const char *remote_peer, const char *client_id, int const char *action = NULL; const char *target = NULL; int timeout = 0; - xmlNode *dev = get_xpath_object("//@" F_STONITH_ACTION, msg, LOG_TRACE); + xmlNode *dev = get_xpath_object("//@" F_STONITH_ACTION, msg, LOG_NEVER); crm_element_value_int(msg, F_STONITH_TIMEOUT, &timeout); if (dev) { @@ -2703,7 +2703,7 @@ stonith_command(crm_client_t * client, uint32_t id, uint32_t flags, xmlNode * re */ char *op = crm_element_value_copy(request, F_STONITH_OPERATION); - if (get_xpath_object("//" T_STONITH_REPLY, request, LOG_TRACE)) { + if (get_xpath_object("//" T_STONITH_REPLY, request, LOG_NEVER)) { is_reply = TRUE; } diff --git a/daemons/fenced/fenced_history.c b/daemons/fenced/fenced_history.c index cd08d7460d6..a1f363b38bf 100644 --- a/daemons/fenced/fenced_history.c +++ b/daemons/fenced/fenced_history.c @@ -1,5 +1,7 @@ /* - * Copyright 2009-2018 Andrew Beekhof + * Copyright 2009-2019 the Pacemaker project contributors + * + * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. @@ -398,7 +400,7 @@ stonith_fence_history(xmlNode *msg, xmlNode **output, { int rc = 0; const char *target = NULL; - xmlNode *dev = get_xpath_object("//@" F_STONITH_TARGET, msg, LOG_TRACE); + xmlNode *dev = get_xpath_object("//@" F_STONITH_TARGET, msg, LOG_NEVER); xmlNode *out_history = NULL; if (dev) { @@ -439,8 +441,8 @@ stonith_fence_history(xmlNode *msg, xmlNode **output, NULL); } else if (remote_peer && !safe_str_eq(remote_peer, stonith_our_uname)) { - xmlNode *history = - get_xpath_object("//" F_STONITH_HISTORY_LIST, msg, LOG_TRACE); + xmlNode *history = get_xpath_object("//" F_STONITH_HISTORY_LIST, + msg, LOG_NEVER); GHashTable *received_history = history?stonith_xml_history_to_list(history):NULL; diff --git a/daemons/fenced/fenced_remote.c b/daemons/fenced/fenced_remote.c index 76a8a0ed572..c2f0a16e332 100644 --- a/daemons/fenced/fenced_remote.c +++ b/daemons/fenced/fenced_remote.c @@ -496,7 +496,8 @@ remote_op_done(remote_fencing_op_t * op, xmlNode * data, int rc, int dup) } if (!op->delegate && data && rc != -ENODEV && rc != -EHOSTUNREACH) { - xmlNode *ndata = get_xpath_object("//@" F_STONITH_DELEGATE, data, LOG_TRACE); + xmlNode *ndata = get_xpath_object("//@" F_STONITH_DELEGATE, data, + LOG_NEVER); if(ndata) { op->delegate = crm_element_value_copy(ndata, F_STONITH_DELEGATE); } else { @@ -963,7 +964,7 @@ void * create_remote_stonith_op(const char *client, xmlNode * request, gboolean peer) { remote_fencing_op_t *op = NULL; - xmlNode *dev = get_xpath_object("//@" F_STONITH_TARGET, request, LOG_TRACE); + xmlNode *dev = get_xpath_object("//@" F_STONITH_TARGET, request, LOG_NEVER); int call_options = 0; init_stonith_remote_op_hash_table(&stonith_remote_op_list); diff --git a/daemons/fenced/pacemaker-fenced.c b/daemons/fenced/pacemaker-fenced.c index 7ef4ac08215..08d04295655 100644 --- a/daemons/fenced/pacemaker-fenced.c +++ b/daemons/fenced/pacemaker-fenced.c @@ -885,7 +885,7 @@ node_has_attr(const char *node, const char *name, const char *value) "/" XML_CIB_TAG_NODE "[@uname='%s']/" XML_TAG_ATTR_SETS "/" XML_CIB_TAG_NVPAIR "[@name='%s' and @value='%s']", node, name, value); - match = get_xpath_object(xpath, local_cib, LOG_TRACE); + match = get_xpath_object(xpath, local_cib, LOG_NEVER); CRM_CHECK(n < XPATH_MAX, return FALSE); return (match != NULL); @@ -1051,7 +1051,8 @@ update_cib_cache_cb(const char *event, xmlNode * msg) crm_peer_caches_refresh(local_cib); - stonith_enabled_xml = get_xpath_object("//nvpair[@name='stonith-enabled']", local_cib, LOG_TRACE); + stonith_enabled_xml = get_xpath_object("//nvpair[@name='stonith-enabled']", + local_cib, LOG_NEVER); if (stonith_enabled_xml) { stonith_enabled_s = crm_element_value(stonith_enabled_xml, XML_NVPAIR_ATTR_VALUE); } @@ -1060,7 +1061,8 @@ update_cib_cache_cb(const char *event, xmlNode * msg) long timeout_ms = 0; const char *value = NULL; - stonith_watchdog_xml = get_xpath_object("//nvpair[@name='stonith-watchdog-timeout']", local_cib, LOG_TRACE); + stonith_watchdog_xml = get_xpath_object("//nvpair[@name='stonith-watchdog-timeout']", + local_cib, LOG_NEVER); if (stonith_watchdog_xml) { value = crm_element_value(stonith_watchdog_xml, XML_NVPAIR_ATTR_VALUE); } diff --git a/daemons/pacemakerd/pacemakerd.c b/daemons/pacemakerd/pacemakerd.c index d8ff53d0cdc..96e02094f4d 100644 --- a/daemons/pacemakerd/pacemakerd.c +++ b/daemons/pacemakerd/pacemakerd.c @@ -779,8 +779,8 @@ mcp_chown(const char *path, uid_t uid, gid_t gid) */ static int pcmk_child_active(pcmk_child_t *child) { - static uid_t cl_uid = 0; - static gid_t cl_gid = 0; + uid_t cl_uid = 0; + gid_t cl_gid = 0; const uid_t root_uid = 0; const gid_t root_gid = 0; const uid_t *ref_uid; @@ -799,8 +799,7 @@ pcmk_child_active(pcmk_child_t *child) { ref_uid = (child->uid != NULL) ? &cl_uid : &root_uid; ref_gid = (child->uid != NULL) ? &cl_gid : &root_gid; - if (child->uid != NULL && !cl_uid && !cl_gid - && crm_user_lookup(CRM_DAEMON_USER, &cl_uid, &cl_gid) < 0) { + if ((child->uid != NULL) && (pcmk_daemon_user(&cl_uid, &cl_gid) < 0)) { crm_err("Could not find user and group IDs for user %s", CRM_DAEMON_USER); ret = -1; @@ -1309,7 +1308,7 @@ main(int argc, char **argv) } } - if (crm_user_lookup(CRM_DAEMON_USER, &pcmk_uid, &pcmk_gid) < 0) { + if (pcmk_daemon_user(&pcmk_uid, &pcmk_gid) < 0) { crm_err("Cluster user %s does not exist, aborting Pacemaker startup", CRM_DAEMON_USER); crm_exit(CRM_EX_NOUSER); } diff --git a/daemons/pacemakerd/pcmkd_corosync.c b/daemons/pacemakerd/pcmkd_corosync.c index 65595facd91..3b1a778a0b9 100644 --- a/daemons/pacemakerd/pcmkd_corosync.c +++ b/daemons/pacemakerd/pcmkd_corosync.c @@ -267,7 +267,7 @@ mcp_read_config(void) if(local_handle){ gid_t gid = 0; - if (crm_user_lookup(CRM_DAEMON_USER, NULL, &gid) < 0) { + if (pcmk_daemon_user(NULL, &gid) < 0) { crm_warn("Could not authorize group with corosync " CRM_XS " No group found for user %s", CRM_DAEMON_USER); diff --git a/doc/Makefile.am b/doc/Makefile.am index 257f5cdf560..a69c7063010 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -8,26 +8,25 @@ # include $(top_srcdir)/Makefile.common -# Deprecated plaintext documents (also dynamically converted to HTML) -ascii = acls.txt \ - crm_fencing.txt -generated_docs = +# Deprecated plaintext documents (dynamically converted to HTML) +DEPRECATED_ORIGINAL = crm_fencing.txt +DEPRECATED_GENERATED = if BUILD_ASCIIDOC -generated_docs += $(ascii:%.txt=%.html) +DEPRECATED_GENERATED += $(DEPRECATED_ORIGINAL:%.txt=%.html) endif +DEPRECATED_ALL = $(DEPRECATED_ORIGINAL) $(DEPRECATED_GENERATED) # Current Publican/docbook-based documentation -docbook = Clusters_from_Scratch \ +BOOKS = Clusters_from_Scratch \ Pacemaker_Administration \ Pacemaker_Development \ Pacemaker_Explained \ Pacemaker_Remote -docbook_build = $(docbook:%=%.build) -doc_DATA = $(ascii) $(generated_docs) +doc_DATA = $(DEPRECATED_ALL) noinst_SCRIPTS = abi-check -EXTRA_DIST = $(ascii) $(SHARED_TXT) $(PNGS_ORIGINAL) $(DOTS) $(SVGS) +EXTRA_DIST = $(DEPRECATED_ORIGINAL) $(SHARED_TXT) $(PNGS_ORIGINAL) $(DOTS) $(SVGS) EXTRA_DIST += $(CFS_TXT) $(CFS_XML_ONLY) EXTRA_DIST += $(PA_TXT) $(PA_XML_ONLY) EXTRA_DIST += $(PD_TXT) $(PD_XML_ONLY) @@ -43,7 +42,9 @@ RSYNC_DEST ?= root@www.clusterlabs.org:/var/www/html RSYNC_OPTS = -rlptvzxS --progress LAST_RELEASE ?= Pacemaker-$(VERSION) -TAG ?= $(shell git log --pretty=format:%H -n 1 HEAD) +TAG ?= $(shell [ -n "`git tag --points-at HEAD | head -1`" ] \ + && ( git tag --points-at HEAD | head -1 ) \ + || git log --pretty=format:%H -n 1 HEAD) # What formats to build by default: pdf,html,html-single,html-desktop,epub DOCBOOK_FORMATS := html-desktop @@ -129,6 +130,24 @@ endif $(AM_V_at)sed -i 's/book>/chapter>/g' $@-t # Rename to chapter (won't trigger if previous sed did) $(AM_V_GEN)mv $@-t $@ +# For Makefile debugging +.PHONY: vars +vars: + @echo DEPRECATED_ORIGINAL=\'$(DEPRECATED_ORIGINAL)\' + @echo DEPRECATED_GENERATED=\'$(DEPRECATED_GENERATED)\' + @echo BOOKS=\'$(BOOKS)\' + @echo LAST_RELEASE=\'$(LAST_RELEASE)\' + @echo TAG=\'$(TAG)\' + + +.PHONY: deprecated-upload +deprecated-upload: $(DEPRECATED_ALL) + rsync $(RSYNC_OPTS) $(DEPRECATED_ALL) "$(RSYNC_DEST)/$(PACKAGE)/doc/" + +.PHONY: deprecated-clean +deprecated-clean: + -rm -f $(DEPRECATED_GENERATED) + # publican-clusterlabs/xsl/{html,html-single,pdf}.xsl refer to URIs # requiring Internet access, hence we shadow that with a XML catalog-based # redirect to local files brought with Publican installation; @@ -183,14 +202,14 @@ CFS_DEPS = $(PNGS) $(CFS_SHARED_XML) $(CFS_XML_ONLY) $(CFS_XML_GEN) # We have to hardcode the book name # With '%' the test for 'newness' fails Clusters_from_Scratch.build: $(CFS_DEPS) $(PUBLICAN_INTREE_DEPS) - @echo Building $(@:%.build=%) because of $? - rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp + @echo "Building $(@:%.build=%) because of $?" + rm -rf "$(@:%.build=%)/publish"/* "$(@:%.build=%)/tmp" $(AM_V_PUB)cd $(@:%.build=%) && RPM_BUILD_DIR="" $(PUBLICAN_INTREE_ENV) \ $(PUBLICAN) build --src_dir="$(srcdir)" --publish \ --langs="$(DOCBOOK_LANGS)" --formats="$(DOCBOOK_FORMATS)" \ $(PUBLICAN_INTREE_OPT) $(PCMK_quiet) - rm -rf $(@:%.build=%)/tmp - touch $@ + rm -rf "$(@:%.build=%)/tmp" + touch "$@" # Pacemaker Administration @@ -213,7 +232,7 @@ Pacemaker_Administration.build: $(PA_DEPS) $(PUBLICAN_INTREE_DEPS) --langs="$(DOCBOOK_LANGS)" --formats="$(DOCBOOK_FORMATS)" \ $(PUBLICAN_INTREE_OPT) $(PCMK_quiet) rm -rf $(@:%.build=%)/tmp - touch $@ + touch "$@" # Pacemaker Development @@ -235,7 +254,7 @@ Pacemaker_Development.build: $(PD_DEPS) $(PUBLICAN_INTREE_DEPS) --langs="$(DOCBOOK_LANGS)" --formats="$(DOCBOOK_FORMATS)" \ $(PUBLICAN_INTREE_OPT) $(PCMK_quiet) rm -rf $(@:%.build=%)/tmp - touch $@ + touch "$@" # Pacemaker Explained @@ -260,7 +279,7 @@ Pacemaker_Explained.build: $(PE_DEPS) $(PUBLICAN_INTREE_DEPS) --langs="$(DOCBOOK_LANGS)" --formats="$(DOCBOOK_FORMATS)" \ $(PUBLICAN_INTREE_OPT) $(PCMK_quiet) rm -rf $(@:%.build=%)/tmp - touch $@ + touch "$@" # Pacemaker Remote @@ -270,11 +289,11 @@ PR_XML_GEN = $(PR_TXT:%.txt=%.xml) PR_XML_ONLY = $(addprefix $(srcdir)/Pacemaker_Remote/en-US/,$(COMMON_XML) \ Pacemaker_Remote.ent \ Pacemaker_Remote.xml) -PR_DEPS = $(PR_XML_ONLY) $(PR_XML_GEN) +PR_DEPS = $(PNGS) $(PR_XML_ONLY) $(PR_XML_GEN) # We have to hardcode the book name # With '%' the test for 'newness' fails -Pacemaker_Remote.build: $(PNGS) $(PR_DEPS) $(PUBLICAN_INTREE_DEPS) +Pacemaker_Remote.build: $(PR_DEPS) $(PUBLICAN_INTREE_DEPS) @echo Building $(@:%.build=%) because of $? rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp $(AM_V_PUB)cd $(@:%.build=%) && RPM_BUILD_DIR="" $(PUBLICAN_INTREE_ENV) \ @@ -282,12 +301,51 @@ Pacemaker_Remote.build: $(PNGS) $(PR_DEPS) $(PUBLICAN_INTREE_DEPS) --langs="$(DOCBOOK_LANGS)" --formats="$(DOCBOOK_FORMATS)" \ $(PUBLICAN_INTREE_OPT) $(PCMK_quiet) rm -rf $(@:%.build=%)/tmp - touch $@ + touch "$@" + + +# Build all books for upload to ClusterLabs +.PHONY: books +books: books-clean +if BUILD_DOCBOOK + for book in $(BOOKS); do \ + sed -i.sed 's@^brand:.*@brand: clusterlabs@' $$book/publican.cfg; \ + done + $(MAKE) $(AM_MAKEFLAGS) DOCBOOK_FORMATS="pdf,html,html-single,epub" \ + DOCBOOK_LANGS="$(DOCBOOK_LANGS)" all-local +endif + +.PHONY: books-upload +books-upload: books +if BUILD_DOCBOOK + @echo Uploading current $(PACKAGE_SERIES) documentation set to clusterlabs.org + @for book in $(BOOKS); do \ + echo Uploading $$book...; \ + echo "Generated on `date` from version: $(shell git log --pretty="format:%h %d" -n 1)" \ + >> $$book/publish/build-$(PACKAGE_SERIES).txt; \ + rsync $(RSYNC_OPTS) $$book/publish/* "$(RSYNC_DEST)/$(PACKAGE)/doc/"; \ + done +endif + +.PHONY: books-clean +books-clean: + -for book in $(BOOKS); do \ + rm -rf $$book/tmp $$book/publish; \ + done + -rm -f $(PNGS_GENERATED) \ + $(SHARED_XML) \ + $(CFS_XML_GEN) \ + $(PA_XML_GEN) \ + $(PD_XML_GEN) \ + $(PE_XML_GEN) \ + $(PR_XML_GEN) \ + publican-catalog-fallback \ + publican-catalog # Update the translation template pot: - @for book in $(docbook); do \ + @for book in $(BOOKS); do \ echo "Updating translation templates in: $$book"; \ ( cd $$book && RPM_BUILD_DIR="" \ $(PUBLICAN) --src_dir="$(srcdir)" update_pot ); \ @@ -295,7 +353,7 @@ pot: # Update the actual translations po: pot - @for book in $(docbook); do \ + @for book in $(BOOKS); do \ echo "Updating translations in: $$book"; \ ( cd $$book && RPM_BUILD_DIR="" \ $(PUBLICAN) --src_dir="$(srcdir)" update_po \ @@ -303,10 +361,10 @@ po: pot done if BUILD_DOCBOOK -all-local: $(docbook_build) */publican.cfg +all-local: $(BOOKS:%=%.build) */publican.cfg install-data-local: all-local - for book in $(docbook); do \ + for book in $(BOOKS); do \ filelist=`find $$book/publish/* -print`; \ for f in $$filelist; do \ p=`echo $$f | sed s:publish/:: | sed s:Pacemaker/::`; \ @@ -401,39 +459,8 @@ abi-clean: # All HTML documentation (except ABI compatibility, which is run separately) +.PHONY: www +www: clean-local deprecated-upload manhtml-upload global-upload doxygen-upload books-upload -www: clean-local $(doc_DATA) manhtml-upload global-upload doxygen-upload -if BUILD_DOCBOOK - for book in $(docbook); do \ - sed -i.sed 's@^brand:.*@brand: clusterlabs@' $$book/publican.cfg; \ - done -endif - $(MAKE) $(AM_MAKEFLAGS) DOCBOOK_FORMATS="pdf,html,html-single,epub" \ - DOCBOOK_LANGS="$(DOCBOOK_LANGS)" all-local - @echo Uploading current $(PACKAGE_SERIES) documentation set to clusterlabs.org -if BUILD_DOCBOOK - @for book in $(docbook); do \ - echo Uploading $$book...; \ - echo "Generated on `date` from version: $(shell git log --pretty="format:%h %d" -n 1)" >> $$book/publish/build-$(PACKAGE_SERIES).txt; \ - rsync $(RSYNC_OPTS) $$book/publish/* "$(RSYNC_DEST)/$(PACKAGE)/doc/"; \ - done -endif - rsync $(RSYNC_OPTS) $(doc_DATA) "$(RSYNC_DEST)/$(PACKAGE)/doc/" - -ALL_GEN = $(generated_docs) \ - $(docbook_build) \ - $(PNGS_GENERATED) \ - $(SHARED_XML) \ - $(CFS_XML_GEN) \ - $(PA_XML_GEN) \ - $(PD_XML_GEN) \ - $(PE_XML_GEN) \ - $(PR_XML_GEN) \ - publican-catalog-fallback \ - publican-catalog - -clean-local: brand-rpm-clean global-clean manhtml-clean doxygen-clean abi-clean - -rm -f $(ALL_GEN) - -for book in $(docbook); do \ - rm -rf $$book/tmp $$book/publish; \ - done + +clean-local: brand-rpm-clean global-clean manhtml-clean doxygen-clean abi-clean books-clean deprecated-clean diff --git a/doc/acls.txt b/doc/acls.txt deleted file mode 100644 index 2028856aeb4..00000000000 --- a/doc/acls.txt +++ /dev/null @@ -1,4 +0,0 @@ -Pacemaker Access Control Lists -============================== -This document has been retired. See the Access Control Lists chapter of the -Pacemaker Explained documentation instead. diff --git a/include/crm/common/logging.h b/include/crm/common/logging.h index 72961df2d69..d7fcc1af54c 100644 --- a/include/crm/common/logging.h +++ b/include/crm/common/logging.h @@ -20,10 +20,28 @@ extern "C" { #ifndef CRM_LOGGING__H # define CRM_LOGGING__H +# include # include +/* Define custom log priorities. + * + * syslog(3) uses int for priorities, but libqb's struct qb_log_callsite uses + * uint8_t, so make sure they fit in the latter. + */ + +// Define something even less desired than debug # ifndef LOG_TRACE -# define LOG_TRACE LOG_DEBUG+1 +# define LOG_TRACE (LOG_DEBUG+1) +# endif + +// Print message to stdout instead of logging it +# ifndef LOG_STDOUT +# define LOG_STDOUT 254 +# endif + +// Don't send message anywhere +# ifndef LOG_NEVER +# define LOG_NEVER 255 # endif /* "Extended information" logging support */ @@ -82,6 +100,8 @@ gboolean crm_log_init(const char *entity, uint8_t level, gboolean daemon, void crm_log_args(int argc, char **argv); void crm_log_output_fn(const char *file, const char *function, int line, int level, const char *prefix, const char *output); + +// Log a block of text line by line # define crm_log_output(level, prefix, output) crm_log_output_fn(__FILE__, __FUNCTION__, __LINE__, level, prefix, output) gboolean crm_add_logfile(const char *filename); @@ -112,33 +132,61 @@ unsigned int get_crm_log_level(void); # define CRM_TRACE_INIT_DATA(name) QB_LOG_INIT_DATA(name) #endif +/* Using "switch" instead of "if" in these macro definitions keeps + * static analysis from complaining about constant evaluations + */ + /*! * \brief Log a message * - * \param[in] level Severity at which to log the message - * \param[in] fmt printf-style format string for message + * \param[in] level Priority at which to log the message + * \param[in] fmt printf-style format string literal for message * \param[in] args Any arguments needed by format string + * + * \note This is a macro, and \p level may be evaluated more than once. */ -# define do_crm_log(level, fmt, args...) \ - qb_log_from_external_source(__func__, __FILE__, fmt, level, __LINE__, 0 , ##args) +# define do_crm_log(level, fmt, args...) do { \ + switch (level) { \ + case LOG_STDOUT: \ + printf(fmt "\n" , ##args); \ + break; \ + case LOG_NEVER: \ + break; \ + default: \ + qb_log_from_external_source(__func__, __FILE__, fmt, \ + (level), __LINE__, 0 , ##args); \ + break; \ + } \ + } while (0) /*! * \brief Log a message that is likely to be filtered out * - * \param[in] level Severity at which to log the message + * \param[in] level Priority at which to log the message * \param[in] fmt printf-style format string for message * \param[in] args Any arguments needed by format string + * + * \note This is a macro, and \p level may be evaluated more than once. + * This does nothing when level is LOG_STDOUT. */ -# define do_crm_log_unlikely(level, fmt, args...) do { \ - static struct qb_log_callsite *trace_cs = NULL; \ - if(trace_cs == NULL) { \ - trace_cs = qb_log_callsite_get(__func__, __FILE__, fmt, level, __LINE__, 0); \ - } \ - if (crm_is_callsite_active(trace_cs, level, 0)) { \ - qb_log_from_external_source( \ - __func__, __FILE__, fmt, level, __LINE__, 0 , ##args); \ - } \ - } while(0) +# define do_crm_log_unlikely(level, fmt, args...) do { \ + switch (level) { \ + case LOG_STDOUT: case LOG_NEVER: \ + break; \ + default: { \ + static struct qb_log_callsite *trace_cs = NULL; \ + if (trace_cs == NULL) { \ + trace_cs = qb_log_callsite_get(__func__, __FILE__, fmt, \ + (level), __LINE__, 0); \ + } \ + if (crm_is_callsite_active(trace_cs, (level), 0)) { \ + qb_log_from_external_source(__func__, __FILE__, fmt, \ + (level), __LINE__, 0 , ##args); \ + } \ + } \ + break; \ + } \ + } while (0) # define CRM_LOG_ASSERT(expr) do { \ if(__unlikely((expr) == FALSE)) { \ @@ -166,76 +214,141 @@ unsigned int get_crm_log_level(void); } \ } while(0) -# define do_crm_log_xml(level, text, xml) do { \ - static struct qb_log_callsite *xml_cs = NULL; \ - if(xml_cs == NULL) { \ - xml_cs = qb_log_callsite_get(__func__, __FILE__, "xml-blob", level, __LINE__, 0); \ - } \ - if (crm_is_callsite_active(xml_cs, level, 0)) { \ - log_data_element(level, __FILE__, __FUNCTION__, __LINE__, text, xml, 1, xml_log_option_formatted); \ - } \ +/*! + * \brief Log XML line-by-line in a formatted fashion + * + * \param[in] level Priority at which to log the messages + * \param[in] text Prefix for each line + * \param[in] xml XML to log + * + * \note This is a macro, and \p level may be evaluated more than once. + * This does nothing when level is LOG_STDOUT. + */ +# define do_crm_log_xml(level, text, xml) do { \ + switch (level) { \ + case LOG_STDOUT: case LOG_NEVER: \ + break; \ + default: { \ + static struct qb_log_callsite *xml_cs = NULL; \ + if (xml_cs == NULL) { \ + xml_cs = qb_log_callsite_get(__func__, __FILE__, \ + "xml-blob", (level), __LINE__, 0); \ + } \ + if (crm_is_callsite_active(xml_cs, (level), 0)) { \ + log_data_element((level), __FILE__, __FUNCTION__, \ + __LINE__, text, xml, 1, xml_log_option_formatted); \ + } \ + } \ + break; \ + } \ } while(0) /*! * \brief Log a message as if it came from a different code location * - * \param[in] level Severity at which to log the message + * \param[in] level Priority at which to log the message * \param[in] file Source file name to use instead of __FILE__ * \param[in] function Source function name to use instead of __func__ * \param[in] line Source line number to use instead of __line__ - * \param[in] fmt printf-style format string for message + * \param[in] fmt printf-style format string literal for message * \param[in] args Any arguments needed by format string + * + * \note This is a macro, and \p level may be evaluated more than once. */ -# define do_crm_log_alias(level, file, function, line, fmt, args...) do { \ - if(level > 0) { \ - qb_log_from_external_source(function, file, fmt, level, line, 0 , ##args); \ - } else { \ - printf(fmt "\n" , ##args); \ - } \ - } while(0) +# define do_crm_log_alias(level, file, function, line, fmt, args...) do { \ + switch (level) { \ + case LOG_STDOUT: \ + printf(fmt "\n" , ##args); \ + break; \ + case LOG_NEVER: \ + break; \ + default: \ + qb_log_from_external_source(function, file, fmt, (level), \ + line, 0 , ##args); \ + break; \ + } \ + } while (0) /*! - * \brief Log a message using constant severity + * \brief Log a message using constant priority * - * \param[in] level Severity at which to log the message - * \param[in] fmt printf-style format string for message + * \param[in] level Priority at which to log the message + * \param[in] fmt printf-style format string literal for message * \param[in] args Any arguments needed by format string * - * \note level and fmt /MUST/ be constants else compilation may fail + * \note This is a macro, and \p level may be evaluated more than once. + * This does nothing when level is LOG_STDOUT. */ -# define do_crm_log_always(level, fmt, args...) qb_log(level, fmt , ##args) +# define do_crm_log_always(level, fmt, args...) do { \ + switch (level) { \ + case LOG_STDOUT: case LOG_NEVER: \ + break; \ + default: \ + qb_log((level), fmt , ##args); \ + break; \ + } \ + } while (0) /*! - * \brief Log a system error message + * \brief Send a system error message to both the log and stderr * - * \param[in] level Severity at which to log the message + * \param[in] level Priority at which to log the message * \param[in] fmt printf-style format string for message * \param[in] args Any arguments needed by format string * + * \deprecated One of the other logging functions should be used with + * pcmk_strerror() instead. + * \note This is a macro, and \p level may be evaluated more than once. * \note Because crm_perror() adds the system error message and error number * onto the end of fmt, that information will become extended information * if CRM_XS is used inside fmt and will not show up in syslog. */ -# define crm_perror(level, fmt, args...) do { \ - const char *err = strerror(errno); \ - /* cast to int makes coverity happy when level == 0 */ \ - if (level <= (int)crm_log_level) { \ - fprintf(stderr, fmt ": %s (%d)\n" , ##args, err, errno); \ - } \ - do_crm_log(level, fmt ": %s (%d)" , ##args, err, errno); \ - } while(0) +# define crm_perror(level, fmt, args...) do { \ + switch (level) { \ + case LOG_NEVER: \ + break; \ + default: { \ + const char *err = strerror(errno); \ + /* cast to int makes coverity happy when level == 0 */ \ + if ((level) <= (int) crm_log_level) { \ + fprintf(stderr, fmt ": %s (%d)\n" , ##args, err, errno);\ + } \ + do_crm_log((level), fmt ": %s (%d)" , ##args, err, errno); \ + } \ + break; \ + } \ + } while (0) -# define crm_log_tag(level, tag, fmt, args...) do { \ - static struct qb_log_callsite *trace_tag_cs = NULL; \ - int converted_tag = g_quark_try_string(tag); \ - if(trace_tag_cs == NULL) { \ - trace_tag_cs = qb_log_callsite_get(__func__, __FILE__, fmt, level, __LINE__, converted_tag); \ - } \ - if (crm_is_callsite_active(trace_tag_cs, level, converted_tag)) { \ - qb_log_from_external_source(__func__, __FILE__, fmt, level, \ - __LINE__, converted_tag , ##args); \ - } \ - } while(0) +/*! + * \brief Log a message with a tag (for use with PCMK_trace_tags) + * + * \param[in] level Priority at which to log the message + * \param[in] tag String to tag message with + * \param[in] fmt printf-style format string for message + * \param[in] args Any arguments needed by format string + * + * \note This is a macro, and \p level may be evaluated more than once. + * This does nothing when level is LOG_STDOUT. + */ +# define crm_log_tag(level, tag, fmt, args...) do { \ + switch (level) { \ + case LOG_STDOUT: case LOG_NEVER: \ + break; \ + default: { \ + static struct qb_log_callsite *trace_tag_cs = NULL; \ + int converted_tag = g_quark_try_string(tag); \ + if (trace_tag_cs == NULL) { \ + trace_tag_cs = qb_log_callsite_get(__func__, __FILE__, \ + fmt, (level), __LINE__, converted_tag); \ + } \ + if (crm_is_callsite_active(trace_tag_cs, (level), \ + converted_tag)) { \ + qb_log_from_external_source(__func__, __FILE__, fmt, \ + (level), __LINE__, converted_tag , ##args); \ + } \ + } \ + } \ + } while (0) # define crm_crit(fmt, args...) qb_logt(LOG_CRIT, 0, fmt , ##args) # define crm_err(fmt, args...) qb_logt(LOG_ERR, 0, fmt , ##args) diff --git a/include/crm/common/mainloop.h b/include/crm/common/mainloop.h index 2cfb63e84f2..b443b4e3e88 100644 --- a/include/crm/common/mainloop.h +++ b/include/crm/common/mainloop.h @@ -49,7 +49,6 @@ typedef void (*sighandler_t)(int); # endif sighandler_t crm_signal_handler(int sig, sighandler_t dispatch); -gboolean crm_signal(int sig, void (*dispatch) (int sig)); // deprecated gboolean mainloop_add_signal(int sig, void (*dispatch) (int sig)); @@ -152,6 +151,13 @@ void pcmk_drain_main_loop(GMainLoop *mloop, guint timer_ms, # define G_PRIORITY_MEDIUM (G_PRIORITY_HIGH/2) +#ifndef PCMK__NO_COMPAT +/* Everything here is deprecated and kept only for public API backward + * compatibility. It will be moved to compatibility.h when 2.1.0 is released. + */ +gboolean crm_signal(int sig, void (*dispatch) (int sig)); // deprecated +#endif + #ifdef __cplusplus } #endif diff --git a/include/crm/common/util.h b/include/crm/common/util.h index 1931a90fe6b..50c2d6ee3fa 100644 --- a/include/crm/common/util.h +++ b/include/crm/common/util.h @@ -118,9 +118,6 @@ int char2score(const char *score); char *score2char(int score); char *score2char_stack(int score, char *buf, size_t len); -// deprecated -#define crm_get_interval crm_parse_interval_spec - /* public operation functions (from operations.c) */ gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms); @@ -154,7 +151,6 @@ char *crm_generate_ra_key(const char *standard, const char *provider, const char *type); int crm_parse_agent_spec(const char *spec, char **standard, char **provider, char **type); -bool crm_provider_required(const char *standard); // deprecated int compare_version(const char *version1, const char *version2); @@ -199,6 +195,7 @@ char *crm_generate_uuid(void); bool crm_is_daemon_name(const char *name); int crm_user_lookup(const char *name, uid_t * uid, gid_t * gid); +int pcmk_daemon_user(uid_t *uid, gid_t *gid); #ifdef HAVE_GNUTLS_GNUTLS_H void crm_gnutls_global_init(void); @@ -208,6 +205,18 @@ bool pcmk_acl_required(const char *user); char *pcmk_hostname(void); +#ifndef PCMK__NO_COMPAT +/* Everything here is deprecated and kept only for public API backward + * compatibility. It will be moved to compatibility.h when 2.1.0 is released. + */ + +//! \deprecated Use crm_parse_interval_spec() instead +#define crm_get_interval crm_parse_interval_spec +#endif + +//! \deprecated Use pcmk_get_ra_caps() instead +bool crm_provider_required(const char *standard); + #ifdef __cplusplus } #endif diff --git a/include/crm/pengine/rules.h b/include/crm/pengine/rules.h index 6b96d991106..ebd3148641b 100644 --- a/include/crm/pengine/rules.h +++ b/include/crm/pengine/rules.h @@ -72,6 +72,11 @@ GHashTable *pe_unpack_versioned_parameters(xmlNode *versioned_params, const char char *pe_expand_re_matches(const char *string, pe_re_match_data_t * match_data); +#ifndef PCMK__NO_COMPAT +/* Everything here is deprecated and kept only for public API backward + * compatibility. It will be moved to compatibility.h when 2.1.0 is released. + */ + //! \deprecated Use pe_evaluate_rules() instead gboolean test_ruleset(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now); @@ -108,6 +113,7 @@ void unpack_instance_attributes(xmlNode *top, xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, gboolean overwrite, crm_time_t *now); +#endif #ifdef __cplusplus } diff --git a/include/crm/stonith-ng.h b/include/crm/stonith-ng.h index 418a03c85ef..3637bc7aa0d 100644 --- a/include/crm/stonith-ng.h +++ b/include/crm/stonith-ng.h @@ -420,9 +420,6 @@ void stonith_api_delete(stonith_t * st); void stonith_dump_pending_callbacks(stonith_t * st); -// deprecated (use stonith_get_namespace() instead) -const char *get_stonith_provider(const char *agent, const char *provider); - bool stonith_dispatch(stonith_t * st); stonith_key_value_t *stonith_key_value_add(stonith_key_value_t * kvp, const char *key, @@ -548,6 +545,16 @@ bool stonith_agent_exists(const char *agent, int timeout); */ const char *stonith_action_str(const char *action); +#ifndef PCMK__NO_COMPAT +/* Everything here is deprecated and kept only for public API backward + * compatibility. It will be moved to compatibility.h when 2.1.0 is released. + */ + +//! \deprecated Use stonith_get_namespace() instead +const char *get_stonith_provider(const char *agent, const char *provider); + +#endif + #ifdef __cplusplus } #endif diff --git a/include/crm_internal.h b/include/crm_internal.h index 652f9c46b1d..bccce54ee94 100644 --- a/include/crm_internal.h +++ b/include/crm_internal.h @@ -22,6 +22,11 @@ # include # include +/* This symbol allows us to deprecate public API and prevent internal code from + * using it while still keeping it for backward compatibility. + */ +#define PCMK__NO_COMPAT + /* Dynamic loading of libraries */ void *find_library_function(void **handle, const char *lib, const char *fn, int fatal); diff --git a/include/pcmki/pcmki_scheduler.h b/include/pcmki/pcmki_scheduler.h index 1d9ea56ad5d..ba22ecbf1ba 100644 --- a/include/pcmki/pcmki_scheduler.h +++ b/include/pcmki/pcmki_scheduler.h @@ -82,8 +82,7 @@ extern gboolean unpack_constraints(xmlNode * xml_constraints, pe_working_set_t * extern gboolean shutdown_constraints(node_t * node, action_t * shutdown_op, pe_working_set_t * data_set); -extern gboolean stonith_constraints(node_t * node, action_t * stonith_op, - pe_working_set_t * data_set); +void pcmk__order_vs_fence(pe_action_t *stonith_op, pe_working_set_t *data_set); extern int custom_action_order(resource_t * lh_rsc, char *lh_task, action_t * lh_action, resource_t * rh_rsc, char *rh_task, action_t * rh_action, diff --git a/lib/common/acl.c b/lib/common/acl.c index 48fd619e70c..5ecfb6458c3 100644 --- a/lib/common/acl.c +++ b/lib/common/acl.c @@ -327,7 +327,7 @@ pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user) } else if (p->acls == NULL) { xmlNode *acls = get_xpath_object("//" XML_CIB_TAG_ACLS, - source, LOG_TRACE); + source, LOG_NEVER); free(p->user); p->user = strdup(user); diff --git a/lib/common/ipc.c b/lib/common/ipc.c index fed02f6fcfc..25b6c4cb6d2 100644 --- a/lib/common/ipc.c +++ b/lib/common/ipc.c @@ -364,22 +364,20 @@ crm_client_alloc(void *key) crm_client_t * crm_client_new(qb_ipcs_connection_t * c, uid_t uid_client, gid_t gid_client) { - static gid_t uid_cluster = 0; - static gid_t gid_cluster = 0; + gid_t uid_cluster = 0; + gid_t gid_cluster = 0; crm_client_t *client = NULL; CRM_CHECK(c != NULL, return NULL); - if (uid_cluster == 0) { - if (crm_user_lookup(CRM_DAEMON_USER, &uid_cluster, &gid_cluster) < 0) { - static bool need_log = TRUE; + if (pcmk_daemon_user(&uid_cluster, &gid_cluster) < 0) { + static bool need_log = TRUE; - if (need_log) { - crm_warn("Could not find user and group IDs for user %s", - CRM_DAEMON_USER); - need_log = FALSE; - } + if (need_log) { + crm_warn("Could not find user and group IDs for user %s", + CRM_DAEMON_USER); + need_log = FALSE; } } @@ -955,8 +953,8 @@ crm_ipc_new(const char *name, size_t max_size) bool crm_ipc_connect(crm_ipc_t * client) { - static uid_t cl_uid = 0; - static gid_t cl_gid = 0; + uid_t cl_uid = 0; + gid_t cl_gid = 0; pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0; int rv; @@ -977,9 +975,8 @@ crm_ipc_connect(crm_ipc_t * client) return FALSE; } - if (!cl_uid && !cl_gid - && (rv = crm_user_lookup(CRM_DAEMON_USER, &cl_uid, &cl_gid)) < 0) { - errno = -rv; + rv = pcmk_daemon_user(&cl_uid, &cl_gid); + if (rv < 0) { /* message already omitted */ crm_ipc_close(client); errno = -rv; diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 4d904562b9d..3414025ec25 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -257,7 +257,7 @@ crm_time_log_alias(int log_level, const char *file, const char *function, int li { char *date_s = crm_time_as_string(date_time, flags); - if (log_level < LOG_CRIT) { + if (log_level == LOG_STDOUT) { printf("%s%s%s\n", (prefix? prefix : ""), (prefix? ": " : ""), date_s); } else { diff --git a/lib/common/logging.c b/lib/common/logging.c index 674a4b8c273..80b5f30ee68 100644 --- a/lib/common/logging.c +++ b/lib/common/logging.c @@ -292,7 +292,7 @@ crm_add_logfile(const char *filename) return FALSE; } - if(crm_user_lookup(CRM_DAEMON_USER, &pcmk_uid, &pcmk_gid) == 0) { + if (pcmk_daemon_user(&pcmk_uid, &pcmk_gid) == 0) { if (st.st_gid != pcmk_gid) { /* Wrong group */ fix = TRUE; @@ -349,8 +349,8 @@ crm_add_logfile(const char *filename) /* qb_log_ctl(fd, QB_LOG_CONF_FILE_SYNC, 1); Turn on synchronous writes */ #ifdef HAVE_qb_log_conf_QB_LOG_CONF_MAX_LINE_LEN - // Longer than default, for logging long XML lines - qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_MAX_LINE_LEN, 800); + // Longer than default, for logging long XML lines + qb_log_ctl(fd, QB_LOG_CONF_MAX_LINE_LEN, 800); #endif /* Enable callsites */ @@ -667,7 +667,7 @@ crm_update_callsites(void) static gboolean crm_tracing_enabled(void) { - if (crm_log_level >= LOG_TRACE) { + if (crm_log_level == LOG_TRACE) { return TRUE; } else if (getenv("PCMK_trace_files") || getenv("PCMK_trace_functions") || getenv("PCMK_trace_formats") || getenv("PCMK_trace_tags")) { @@ -803,6 +803,9 @@ crm_log_init(const char *entity, uint8_t level, gboolean daemon, gboolean to_std crm_is_daemon = daemon; crm_log_preinit(entity, argc, argv); + if (level > LOG_TRACE) { + level = LOG_TRACE; + } if(level > crm_log_level) { crm_log_level = level; } @@ -939,6 +942,9 @@ set_crm_log_level(unsigned int level) { unsigned int old = crm_log_level; + if (level > LOG_TRACE) { + level = LOG_TRACE; + } crm_log_level = level; crm_update_callsites(); crm_trace("New log level: %d", level); @@ -1021,8 +1027,14 @@ crm_log_output_fn(const char *file, const char *function, int line, int level, c const char *next = NULL; const char *offset = NULL; + if (level == LOG_NEVER) { + return; + } + if (output == NULL) { - level = LOG_TRACE; + if (level != LOG_STDOUT) { + level = LOG_TRACE; + } output = "-- empty --"; } diff --git a/lib/common/utils.c b/lib/common/utils.c index cb0bc1f4d4f..19fc0a3f751 100644 --- a/lib/common/utils.c +++ b/lib/common/utils.c @@ -407,6 +407,10 @@ crm_user_lookup(const char *name, uid_t * uid, gid_t * gid) struct passwd *pwentry = NULL; buffer = calloc(1, PW_BUFFER_LEN); + if (buffer == NULL) { + return -ENOMEM; + } + rc = getpwnam_r(name, &pwd, buffer, PW_BUFFER_LEN, &pwentry); if (pwentry) { if (uid) { @@ -426,6 +430,39 @@ crm_user_lookup(const char *name, uid_t * uid, gid_t * gid) return rc; } +/*! + * \brief Get user and group IDs of pacemaker daemon user + * + * \param[out] uid If non-NULL, where to store daemon user ID + * \param[out] gid If non-NULL, where to store daemon group ID + * + * \return pcmk_ok on success, -errno otherwise + */ +int +pcmk_daemon_user(uid_t *uid, gid_t *gid) +{ + static uid_t daemon_uid; + static gid_t daemon_gid; + static bool found = false; + int rc = pcmk_err_generic; + + if (!found) { + rc = crm_user_lookup(CRM_DAEMON_USER, &daemon_uid, &daemon_gid); + if (rc == pcmk_ok) { + found = true; + } + } + if (found) { + if (uid) { + *uid = daemon_uid; + } + if (gid) { + *gid = daemon_gid; + } + } + return rc; +} + static int crm_version_helper(const char *text, const char **end_text) { diff --git a/lib/common/xml.c b/lib/common/xml.c index ec6028c3575..544088b8676 100644 --- a/lib/common/xml.c +++ b/lib/common/xml.c @@ -838,6 +838,9 @@ xml_log_patchset(uint8_t log_level, const char *function, xmlNode * patchset) static struct qb_log_callsite *patchset_cs = NULL; + if (log_level == LOG_NEVER) { + return; + } if (patchset_cs == NULL) { patchset_cs = qb_log_callsite_get(function, __FILE__, "xml-patchset", log_level, __LINE__, 0); } @@ -846,9 +849,8 @@ xml_log_patchset(uint8_t log_level, const char *function, xmlNode * patchset) crm_trace("Empty patch"); return; - } else if (log_level == 0) { - /* Log to stdout */ - } else if (crm_is_callsite_active(patchset_cs, log_level, 0) == FALSE) { + } else if ((log_level != LOG_STDOUT) + && !crm_is_callsite_active(patchset_cs, log_level, 0)) { return; } @@ -981,6 +983,10 @@ xml_log_changes(uint8_t log_level, const char *function, xmlNode * xml) GListPtr gIter = NULL; xml_private_t *doc = NULL; + if (log_level == LOG_NEVER) { + return; + } + CRM_ASSERT(xml); CRM_ASSERT(xml->doc); @@ -2760,7 +2766,7 @@ __xml_log_element(int log_level, const char *file, const char *function, int lin xmlNode *child = NULL; xmlAttrPtr pIter = NULL; - if(data == NULL) { + if ((data == NULL) || (log_level == LOG_NEVER)) { return; } @@ -2852,7 +2858,7 @@ __xml_log_change_element(int log_level, const char *file, const char *function, xmlNode *child = NULL; xmlAttrPtr pIter = NULL; - if(data == NULL) { + if ((data == NULL) || (log_level == LOG_NEVER)) { return; } @@ -2947,6 +2953,10 @@ log_data_element(int log_level, const char *file, const char *function, int line char *prefix_m = NULL; + if (log_level == LOG_NEVER) { + return; + } + if (prefix == NULL) { prefix = ""; } diff --git a/lib/common/xpath.c b/lib/common/xpath.c index 9c103b584f4..fa8f88e4d69 100644 --- a/lib/common/xpath.c +++ b/lib/common/xpath.c @@ -1,19 +1,10 @@ /* - * Copyright (C) 2004 Andrew Beekhof + * Copyright 2004-2019 the Pacemaker project contributors * - * 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. + * The version control history for this file may have further details. * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * This source code is licensed under the GNU Lesser General Public License + * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #include @@ -234,25 +225,32 @@ get_xpath_object(const char *xpath, xmlNode * xml_obj, int error_level) max = numXpathResults(xpathObj); if (max < 1) { - do_crm_log(error_level, "No match for %s in %s", xpath, crm_str(nodePath)); - crm_log_xml_explicit(xml_obj, "Unexpected Input"); + if (error_level < LOG_NEVER) { + do_crm_log(error_level, "No match for %s in %s", + xpath, crm_str(nodePath)); + crm_log_xml_explicit(xml_obj, "Unexpected Input"); + } } else if (max > 1) { - int lpc = 0; + if (error_level < LOG_NEVER) { + int lpc = 0; - do_crm_log(error_level, "Too many matches for %s in %s", xpath, crm_str(nodePath)); + do_crm_log(error_level, "Too many matches for %s in %s", + xpath, crm_str(nodePath)); - for (lpc = 0; lpc < max; lpc++) { - xmlNode *match = getXpathResult(xpathObj, lpc); + for (lpc = 0; lpc < max; lpc++) { + xmlNode *match = getXpathResult(xpathObj, lpc); - CRM_LOG_ASSERT(match != NULL); - if(match != NULL) { - matchNodePath = (char *)xmlGetNodePath(match); - do_crm_log(error_level, "%s[%d] = %s", xpath, lpc, crm_str(matchNodePath)); - free(matchNodePath); + CRM_LOG_ASSERT(match != NULL); + if (match != NULL) { + matchNodePath = (char *) xmlGetNodePath(match); + do_crm_log(error_level, "%s[%d] = %s", + xpath, lpc, crm_str(matchNodePath)); + free(matchNodePath); + } } + crm_log_xml_explicit(xml_obj, "Bad Input"); } - crm_log_xml_explicit(xml_obj, "Bad Input"); } else { result = getXpathResult(xpathObj, 0); diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c index 3d0f805b27e..bdaede3b50b 100644 --- a/lib/fencing/st_client.c +++ b/lib/fencing/st_client.c @@ -1119,7 +1119,8 @@ stonith_api_history(stonith_t * stonith, int call_options, const char *node, if (rc == 0) { xmlNode *op = NULL; - xmlNode *reply = get_xpath_object("//" F_STONITH_HISTORY_LIST, output, LOG_TRACE); + xmlNode *reply = get_xpath_object("//" F_STONITH_HISTORY_LIST, output, + LOG_NEVER); for (op = __xml_first_child(reply); op != NULL; op = __xml_next(op)) { stonith_history_t *kvp; @@ -1162,15 +1163,6 @@ void stonith_history_free(stonith_history_t *history) } } -/*! - * \brief Deprecated (use stonith_get_namespace() instead) - */ -const char * -get_stonith_provider(const char *agent, const char *provider) -{ - return stonith_namespace2text(stonith_get_namespace(agent, provider)); -} - static gint stonithlib_GCompareFunc(gconstpointer a, gconstpointer b) { @@ -2595,3 +2587,15 @@ stonith__sort_history(stonith_history_t *history) } return new; } + +// Deprecated functions kept only for backward API compatibility +const char *get_stonith_provider(const char *agent, const char *provider); + +/*! + * \brief Deprecated (use stonith_get_namespace() instead) + */ +const char * +get_stonith_provider(const char *agent, const char *provider) +{ + return stonith_namespace2text(stonith_get_namespace(agent, provider)); +} diff --git a/lib/pacemaker/pcmk_sched_allocate.c b/lib/pacemaker/pcmk_sched_allocate.c index 1a46cc5007d..ca43c71a7d6 100644 --- a/lib/pacemaker/pcmk_sched_allocate.c +++ b/lib/pacemaker/pcmk_sched_allocate.c @@ -1297,6 +1297,7 @@ gboolean stage5(pe_working_set_t * data_set) { GListPtr gIter = NULL; + int log_prio = show_utilization? LOG_STDOUT : utilization_log_level; if (safe_str_neq(data_set->placement_strategy, "default")) { GListPtr nodes = g_list_copy(data_set->nodes); @@ -1312,7 +1313,7 @@ stage5(pe_working_set_t * data_set) for (; gIter != NULL; gIter = gIter->next) { node_t *node = (node_t *) gIter->data; - dump_node_capacity(show_utilization ? 0 : utilization_log_level, "Original", node); + dump_node_capacity(log_prio, "Original", node); } crm_trace("Allocating services"); @@ -1324,7 +1325,7 @@ stage5(pe_working_set_t * data_set) for (; gIter != NULL; gIter = gIter->next) { node_t *node = (node_t *) gIter->data; - dump_node_capacity(show_utilization ? 0 : utilization_log_level, "Remaining", node); + dump_node_capacity(log_prio, "Remaining", node); } // Process deferred action checks @@ -1516,7 +1517,7 @@ fence_guest(pe_node_t *node, pe_working_set_t *data_set) } /* Order/imply other actions relative to pseudo-fence as with real fence */ - stonith_constraints(node, stonith_op, data_set); + pcmk__order_vs_fence(stonith_op, data_set); } /* @@ -1571,7 +1572,7 @@ stage6(pe_working_set_t * data_set) stonith_op = pe_fence_op(node, NULL, FALSE, "node is unclean", data_set); pe_warn("Scheduling Node %s for STONITH", node->details->uname); - stonith_constraints(node, stonith_op, data_set); + pcmk__order_vs_fence(stonith_op, data_set); if (node->details->is_dc) { // Remember if the DC is being fenced diff --git a/lib/pacemaker/pcmk_sched_bundle.c b/lib/pacemaker/pcmk_sched_bundle.c index 6551fe9144e..17e49a6f7fc 100644 --- a/lib/pacemaker/pcmk_sched_bundle.c +++ b/lib/pacemaker/pcmk_sched_bundle.c @@ -112,7 +112,8 @@ pcmk__bundle_color(pe_resource_t *rsc, pe_node_t *prefer, set_bit(rsc->flags, pe_rsc_allocating); containers = get_container_list(rsc); - dump_node_scores(show_scores ? 0 : scores_log_level, rsc, __FUNCTION__, rsc->allowed_nodes); + dump_node_scores((show_scores? LOG_STDOUT : scores_log_level), rsc, + __FUNCTION__, rsc->allowed_nodes); nodes = g_hash_table_get_values(rsc->allowed_nodes); nodes = sort_nodes_by_weight(nodes, NULL, data_set); diff --git a/lib/pacemaker/pcmk_sched_clone.c b/lib/pacemaker/pcmk_sched_clone.c index e661d76481b..7d93e1b1841 100644 --- a/lib/pacemaker/pcmk_sched_clone.c +++ b/lib/pacemaker/pcmk_sched_clone.c @@ -1,5 +1,7 @@ /* - * Copyright 2004-2019 Andrew Beekhof + * Copyright 2004-2019 the Pacemaker project contributors + * + * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. @@ -630,7 +632,8 @@ clone_color(resource_t *rsc, node_t *prefer, pe_working_set_t *data_set) (pe_weights_rollback | pe_weights_positive)); } - dump_node_scores(show_scores ? 0 : scores_log_level, rsc, __FUNCTION__, rsc->allowed_nodes); + dump_node_scores((show_scores? LOG_STDOUT : scores_log_level), rsc, + __FUNCTION__, rsc->allowed_nodes); nodes = g_hash_table_get_values(rsc->allowed_nodes); nodes = sort_nodes_by_weight(nodes, NULL, data_set); diff --git a/lib/pacemaker/pcmk_sched_graph.c b/lib/pacemaker/pcmk_sched_graph.c index 744d9a540fe..e5a8a0129de 100644 --- a/lib/pacemaker/pcmk_sched_graph.c +++ b/lib/pacemaker/pcmk_sched_graph.c @@ -754,20 +754,16 @@ shutdown_constraints(node_t * node, action_t * shutdown_op, pe_working_set_t * d * imply stop and demote operations of affected resources by marking them as * pseudo-actions, etc. * - * \param[in] node Node to be fenced * \param[in] stonith_op Fencing operation * \param[in,out] data_set Working set of cluster */ -gboolean -stonith_constraints(node_t * node, action_t * stonith_op, pe_working_set_t * data_set) +void +pcmk__order_vs_fence(pe_action_t *stonith_op, pe_working_set_t *data_set) { - GListPtr r = NULL; - - CRM_CHECK(stonith_op != NULL, return FALSE); - for (r = data_set->resources; r != NULL; r = r->next) { - rsc_stonith_ordering((resource_t *) r->data, stonith_op, data_set); + CRM_CHECK(stonith_op && data_set, return); + for (GList *r = data_set->resources; r != NULL; r = r->next) { + rsc_stonith_ordering((pe_resource_t *) r->data, stonith_op, data_set); } - return TRUE; } static node_t * diff --git a/lib/pacemaker/pcmk_sched_group.c b/lib/pacemaker/pcmk_sched_group.c index e12774f0335..9a81f26af76 100644 --- a/lib/pacemaker/pcmk_sched_group.c +++ b/lib/pacemaker/pcmk_sched_group.c @@ -1,5 +1,7 @@ /* - * Copyright 2004-2018 Andrew Beekhof + * Copyright 2004-2019 the Pacemaker project contributors + * + * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. @@ -34,7 +36,7 @@ group_color(resource_t * rsc, node_t * prefer, pe_working_set_t * data_set) } if (group_data->first_child == NULL) { - /* nothign to allocate */ + // Nothing to allocate clear_bit(rsc->flags, pe_rsc_provisional); return NULL; } @@ -50,8 +52,8 @@ group_color(resource_t * rsc, node_t * prefer, pe_working_set_t * data_set) g_list_concat(group_data->last_child->rsc_cons_lhs, rsc->rsc_cons_lhs); rsc->rsc_cons_lhs = NULL; - dump_node_scores(show_scores ? 0 : scores_log_level, rsc, __FUNCTION__, - rsc->allowed_nodes); + dump_node_scores((show_scores? LOG_STDOUT : scores_log_level), rsc, + __FUNCTION__, rsc->allowed_nodes); gIter = rsc->children; for (; gIter != NULL; gIter = gIter->next) { diff --git a/lib/pacemaker/pcmk_sched_messages.c b/lib/pacemaker/pcmk_sched_messages.c index 6eecddc25e4..3a91b4eb7c3 100644 --- a/lib/pacemaker/pcmk_sched_messages.c +++ b/lib/pacemaker/pcmk_sched_messages.c @@ -118,7 +118,7 @@ pcmk__schedule_actions(pe_working_set_t *data_set, xmlNode *xml_input, crm_trace("=#=#=#=#= Summary =#=#=#=#="); crm_trace("\t========= Set %d (Un-runnable) =========", -1); - if (get_crm_log_level() >= LOG_TRACE) { + if (get_crm_log_level() == LOG_TRACE) { gIter = data_set->actions; for (; gIter != NULL; gIter = gIter->next) { action_t *action = (action_t *) gIter->data; diff --git a/lib/pacemaker/pcmk_sched_native.c b/lib/pacemaker/pcmk_sched_native.c index bbf3eb73327..38e90bf467d 100644 --- a/lib/pacemaker/pcmk_sched_native.c +++ b/lib/pacemaker/pcmk_sched_native.c @@ -509,8 +509,8 @@ native_color(resource_t * rsc, node_t * prefer, pe_working_set_t * data_set) rsc->next_role = rsc->role; } - dump_node_scores(show_scores ? 0 : scores_log_level, rsc, __FUNCTION__, - rsc->allowed_nodes); + dump_node_scores((show_scores? LOG_STDOUT : scores_log_level), rsc, + __FUNCTION__, rsc->allowed_nodes); if (is_set(data_set->flags, pe_flag_stonith_enabled) && is_set(data_set->flags, pe_flag_have_stonith_resource) == FALSE) { clear_bit(rsc->flags, pe_rsc_managed); diff --git a/lib/pacemaker/pcmk_sched_utils.c b/lib/pacemaker/pcmk_sched_utils.c index d8a9a25b5d8..795930ee5cd 100644 --- a/lib/pacemaker/pcmk_sched_utils.c +++ b/lib/pacemaker/pcmk_sched_utils.c @@ -281,7 +281,8 @@ native_assign_node(resource_t * rsc, GListPtr nodes, node_t * chosen, gboolean f chosen->details->num_resources++; chosen->count++; calculate_utilization(chosen->details->utilization, rsc->utilization, FALSE); - dump_rsc_utilization(show_utilization ? 0 : utilization_log_level, __FUNCTION__, rsc, chosen); + dump_rsc_utilization((show_utilization? LOG_STDOUT : utilization_log_level), + __FUNCTION__, rsc, chosen); return TRUE; } diff --git a/lib/pacemaker/pcmk_trans_utils.c b/lib/pacemaker/pcmk_trans_utils.c index 7e840b9bdf9..250c68e8a47 100644 --- a/lib/pacemaker/pcmk_trans_utils.c +++ b/lib/pacemaker/pcmk_trans_utils.c @@ -238,7 +238,7 @@ print_graph(unsigned int log_level, crm_graph_t * graph) GListPtr lpc = NULL; if (graph == NULL || graph->num_actions == 0) { - if (log_level > LOG_DEBUG) { + if (log_level == LOG_TRACE) { crm_debug("Empty transition graph"); } return; diff --git a/lib/pengine/bundle.c b/lib/pengine/bundle.c index ebfd58582dc..fa8d778730e 100644 --- a/lib/pengine/bundle.c +++ b/lib/pengine/bundle.c @@ -730,9 +730,9 @@ create_remote_resource(pe_resource_t *parent, pe__bundle_variant_data_t *data, } /* This sets replica->container as replica->remote's container, which is - * similar to what happens with guest nodes. This is how the PE knows - * that the bundle node is fenced by recovering the container, and that - * remote should be ordered relative to the container. + * similar to what happens with guest nodes. This is how the scheduler + * knows that the bundle node is fenced by recovering the container, and + * that remote should be ordered relative to the container. */ xml_remote = pe_create_remote_xml(NULL, id, replica->container->id, NULL, NULL, NULL, diff --git a/lib/pengine/rules.c b/lib/pengine/rules.c index 69f41cc805f..ad9df76fa61 100644 --- a/lib/pengine/rules.c +++ b/lib/pengine/rules.c @@ -59,29 +59,6 @@ pe_evaluate_rules(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now, return ruleset_default; } -gboolean -test_ruleset(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now) -{ - return pe_evaluate_rules(ruleset, node_hash, now, NULL); -} - -gboolean -test_rule(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now) -{ - return pe_test_rule(rule, node_hash, role, now, NULL, NULL); -} - -gboolean -pe_test_rule_re(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now, pe_re_match_data_t * re_match_data) -{ - pe_match_data_t match_data = { - .re = re_match_data, - .params = NULL, - .meta = NULL, - }; - return pe_test_rule(rule, node_hash, role, now, NULL, &match_data); -} - gboolean pe_test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now, crm_time_t *next_change, @@ -127,30 +104,6 @@ pe_test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, return passed; } -gboolean -pe_test_rule_full(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, - crm_time_t *now, pe_match_data_t *match_data) -{ - return pe_test_rule(rule, node_hash, role, now, NULL, match_data); -} - -gboolean -test_expression(xmlNode * expr, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now) -{ - return pe_test_expression(expr, node_hash, role, now, NULL, NULL); -} - -gboolean -pe_test_expression_re(xmlNode * expr, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now, pe_re_match_data_t * re_match_data) -{ - pe_match_data_t match_data = { - .re = re_match_data, - .params = NULL, - .meta = NULL, - }; - return pe_test_expression(expr, node_hash, role, now, NULL, &match_data); -} - /*! * \brief Evaluate one rule subelement (pass/fail) * @@ -224,14 +177,6 @@ pe_test_expression(xmlNode *expr, GHashTable *node_hash, enum rsc_role_e role, return accept; } -gboolean -pe_test_expression_full(xmlNode *expr, GHashTable *node_hash, - enum rsc_role_e role, crm_time_t *now, - pe_match_data_t *match_data) -{ - return pe_test_expression(expr, node_hash, role, now, NULL, match_data); -} - enum expression_type find_expression_type(xmlNode * expr) { @@ -1059,16 +1004,6 @@ pe_unpack_nvpairs(xmlNode *top, xmlNode *xml_obj, const char *set_name, overwrite, now, next_change, unpack_attr_set); } -void -unpack_instance_attributes(xmlNode *top, xmlNode *xml_obj, const char *set_name, - GHashTable *node_hash, GHashTable *hash, - const char *always_first, gboolean overwrite, - crm_time_t *now) -{ - unpack_nvpair_blocks(top, xml_obj, set_name, node_hash, hash, always_first, - overwrite, now, NULL, unpack_attr_set); -} - #if ENABLE_VERSIONED_ATTRS void pe_unpack_versioned_attributes(xmlNode *top, xmlNode *xml_obj, @@ -1162,3 +1097,91 @@ pe_unpack_versioned_parameters(xmlNode *versioned_params, const char *ra_version return hash; } #endif + +// Deprecated functions kept only for backward API compatibility +gboolean test_ruleset(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now); +gboolean test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, + crm_time_t *now); +gboolean pe_test_rule_re(xmlNode *rule, GHashTable *node_hash, + enum rsc_role_e role, crm_time_t *now, + pe_re_match_data_t *re_match_data); +gboolean pe_test_rule_full(xmlNode *rule, GHashTable *node_hash, + enum rsc_role_e role, crm_time_t *now, + pe_match_data_t *match_data); +gboolean test_expression(xmlNode *expr, GHashTable *node_hash, + enum rsc_role_e role, crm_time_t *now); +gboolean pe_test_expression_re(xmlNode *expr, GHashTable *node_hash, + enum rsc_role_e role, crm_time_t *now, + pe_re_match_data_t *re_match_data); +gboolean pe_test_expression_full(xmlNode *expr, GHashTable *node_hash, + enum rsc_role_e role, crm_time_t *now, + pe_match_data_t *match_data); +void unpack_instance_attributes(xmlNode *top, xmlNode *xml_obj, + const char *set_name, GHashTable *node_hash, + GHashTable *hash, const char *always_first, + gboolean overwrite, crm_time_t *now); + +gboolean +test_ruleset(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now) +{ + return pe_evaluate_rules(ruleset, node_hash, now, NULL); +} + +gboolean +test_rule(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now) +{ + return pe_test_rule(rule, node_hash, role, now, NULL, NULL); +} + +gboolean +pe_test_rule_re(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now, pe_re_match_data_t * re_match_data) +{ + pe_match_data_t match_data = { + .re = re_match_data, + .params = NULL, + .meta = NULL, + }; + return pe_test_rule(rule, node_hash, role, now, NULL, &match_data); +} + +gboolean +pe_test_rule_full(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, + crm_time_t *now, pe_match_data_t *match_data) +{ + return pe_test_rule(rule, node_hash, role, now, NULL, match_data); +} + +gboolean +test_expression(xmlNode * expr, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now) +{ + return pe_test_expression(expr, node_hash, role, now, NULL, NULL); +} + +gboolean +pe_test_expression_re(xmlNode * expr, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now, pe_re_match_data_t * re_match_data) +{ + pe_match_data_t match_data = { + .re = re_match_data, + .params = NULL, + .meta = NULL, + }; + return pe_test_expression(expr, node_hash, role, now, NULL, &match_data); +} + +gboolean +pe_test_expression_full(xmlNode *expr, GHashTable *node_hash, + enum rsc_role_e role, crm_time_t *now, + pe_match_data_t *match_data) +{ + return pe_test_expression(expr, node_hash, role, now, NULL, match_data); +} + +void +unpack_instance_attributes(xmlNode *top, xmlNode *xml_obj, const char *set_name, + GHashTable *node_hash, GHashTable *hash, + const char *always_first, gboolean overwrite, + crm_time_t *now) +{ + unpack_nvpair_blocks(top, xml_obj, set_name, node_hash, hash, always_first, + overwrite, now, NULL, unpack_attr_set); +} diff --git a/lib/pengine/status.c b/lib/pengine/status.c index 1ef1488e9b0..8a8c1727fe0 100644 --- a/lib/pengine/status.c +++ b/lib/pengine/status.c @@ -1,5 +1,7 @@ /* - * Copyright 2004-2018 Andrew Beekhof + * Copyright 2004-2019 the Pacemaker project contributors + * + * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. @@ -71,7 +73,8 @@ cluster_status(pe_working_set_t * data_set) xmlNode *cib_nodes = get_xpath_object("//"XML_CIB_TAG_NODES, data_set->input, LOG_TRACE); xmlNode *cib_resources = get_xpath_object("//"XML_CIB_TAG_RESOURCES, data_set->input, LOG_TRACE); xmlNode *cib_status = get_xpath_object("//"XML_CIB_TAG_STATUS, data_set->input, LOG_TRACE); - xmlNode *cib_tags = get_xpath_object("//"XML_CIB_TAG_TAGS, data_set->input, LOG_TRACE); + xmlNode *cib_tags = get_xpath_object("//" XML_CIB_TAG_TAGS, data_set->input, + LOG_NEVER); const char *value = crm_element_value(data_set->input, XML_ATTR_HAVE_QUORUM); crm_trace("Beginning unpack"); @@ -97,8 +100,10 @@ cluster_status(pe_working_set_t * data_set) set_bit(data_set->flags, pe_flag_have_quorum); } - data_set->op_defaults = get_xpath_object("//"XML_CIB_TAG_OPCONFIG, data_set->input, LOG_TRACE); - data_set->rsc_defaults = get_xpath_object("//"XML_CIB_TAG_RSCCONFIG, data_set->input, LOG_TRACE); + data_set->op_defaults = get_xpath_object("//" XML_CIB_TAG_OPCONFIG, + data_set->input, LOG_NEVER); + data_set->rsc_defaults = get_xpath_object("//" XML_CIB_TAG_RSCCONFIG, + data_set->input, LOG_NEVER); unpack_config(config, data_set); diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c index d33775838ca..e2039aa74af 100644 --- a/lib/pengine/unpack.c +++ b/lib/pengine/unpack.c @@ -674,7 +674,7 @@ unpack_remote_nodes(xmlNode * xml_resources, pe_working_set_t * data_set) * A remote node's online status is reflected by the state * of the remote node's connection resource. We need to link * the remote node to this connection resource so we can have - * easy access to the connection resource during the PE calculations. + * easy access to the connection resource during the scheduler calculations. */ static void link_rsc2remotenode(pe_working_set_t *data_set, resource_t *new_rsc) @@ -1167,7 +1167,8 @@ unpack_status(xmlNode * status, pe_working_set_t * data_set) && this_node->details->online && (data_set->no_quorum_policy == no_quorum_suicide)) { /* Everything else should flow from this automatically - * At least until the PE becomes able to migrate off healthy resources + * (at least until the scheduler becomes able to migrate off + * healthy resources) */ pe_fence_node(data_set, this_node, "cluster does not have quorum"); } @@ -2813,11 +2814,10 @@ unpack_rsc_op_failure(resource_t * rsc, node_t * node, int rc, xmlNode * xml_op, rsc->role = RSC_ROLE_STOPPED; } else { - /* - * Staying in master role would put the PE/TE into a loop. Setting - * slave role is not dangerous because the resource will be stopped - * as part of recovery, and any master promotion will be ordered - * after that stop. + /* Staying in master role would put the scheduler and controller + * into a loop. Setting slave role is not dangerous because the + * resource will be stopped as part of recovery, and any master + * promotion will be ordered after that stop. */ rsc->role = RSC_ROLE_SLAVE; } diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c index 3fc072f9965..6f3f48443db 100644 --- a/lib/pengine/utils.c +++ b/lib/pengine/utils.c @@ -287,6 +287,9 @@ dump_node_scores_worker(int level, const char *file, const char *function, int l GHashTableIter iter; node_t *node = NULL; + if (level == LOG_NEVER) { + return; + } if (rsc) { hash = rsc->allowed_nodes; } @@ -296,7 +299,7 @@ dump_node_scores_worker(int level, const char *file, const char *function, int l return; } - if (level == 0) { + if (level == LOG_STDOUT) { char score[128]; int len = sizeof(score); /* For now we want this in sorted order to keep the regression tests happy */ @@ -371,7 +374,7 @@ dump_node_capacity(int level, const char *comment, node_t * node) g_hash_table_foreach(node->details->utilization, append_dump_text, &dump_text); - if (level == 0) { + if (level == LOG_STDOUT) { fprintf(stdout, "%s\n", dump_text); } else { crm_trace("%s", dump_text); @@ -387,13 +390,15 @@ dump_rsc_utilization(int level, const char *comment, resource_t * rsc, node_t * comment, rsc->id, node->details->uname); g_hash_table_foreach(rsc->utilization, append_dump_text, &dump_text); - - if (level == 0) { - fprintf(stdout, "%s\n", dump_text); - } else { - crm_trace("%s", dump_text); + switch (level) { + case LOG_STDOUT: + fprintf(stdout, "%s\n", dump_text); + break; + case LOG_NEVER: + break; + default: + crm_trace("%s", dump_text); } - free(dump_text); } diff --git a/lib/services/Makefile.am b/lib/services/Makefile.am index 6dd423be231..e85732e7104 100644 --- a/lib/services/Makefile.am +++ b/lib/services/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2012-2018 the Pacemaker project contributors +# Copyright 2012-2019 the Pacemaker project contributors # # The version control history for this file may have further details. # @@ -13,7 +13,8 @@ AM_CPPFLAGS = -I$(top_srcdir)/include lib_LTLIBRARIES = libcrmservice.la noinst_HEADERS = pcmk-dbus.h upstart.h systemd.h \ - services_lsb.h services_private.h + services_lsb.h services_nagios.h \ + services_private.h libcrmservice_la_LDFLAGS = -version-info 30:0:2 libcrmservice_la_CPPFLAGS = -DOCF_ROOT_DIR=\"@OCF_ROOT_DIR@\" $(AM_CPPFLAGS) @@ -24,7 +25,9 @@ libcrmservice_la_LDFLAGS += $(LDFLAGS_HARDENED_LIB) libcrmservice_la_LIBADD = $(top_builddir)/lib/common/libcrmcommon.la $(DBUS_LIBS) -libcrmservice_la_SOURCES = services.c services_linux.c services_lsb.c +libcrmservice_la_SOURCES = services.c +libcrmservice_la_SOURCES += services_linux.c +libcrmservice_la_SOURCES += services_lsb.c if BUILD_DBUS libcrmservice_la_SOURCES += dbus.c endif @@ -34,3 +37,6 @@ endif if BUILD_SYSTEMD libcrmservice_la_SOURCES += systemd.c endif +if BUILD_NAGIOS +libcrmservice_la_SOURCES += services_nagios.c +endif diff --git a/lib/services/services.c b/lib/services/services.c index db6a4a06d2f..3366b3281a7 100644 --- a/lib/services/services.c +++ b/lib/services/services.c @@ -1,5 +1,7 @@ /* - * Copyright 2010-2019 Andrew Beekhof + * Copyright 2010-2019 the Pacemaker project contributors + * + * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. @@ -34,6 +36,10 @@ # include #endif +#if SUPPORT_NAGIOS +# include +#endif + /* TODO: Develop a rollover strategy */ static int operations = 0; @@ -564,11 +570,11 @@ services_action_cancel(const char *name, const char *action, guint interval_ms) * goes away. */ if (op->pid != 0) { - crm_info("Terminating in-flight op %s (pid %d) early because it was cancelled", + crm_info("Terminating in-flight op %s[%d] early because it was cancelled", id, op->pid); cancelled = mainloop_child_kill(op->pid); if (cancelled == FALSE) { - crm_err("Termination of %s (pid %d) failed", id, op->pid); + crm_err("Termination of %s[%d] failed", id, op->pid); } goto done; } @@ -825,57 +831,6 @@ handle_blocked_ops(void) processing_blocked_ops = FALSE; } -#if SUPPORT_NAGIOS -static int -nagios_get_metadata(const char *type, char **output) -{ - int rc = pcmk_ok; - FILE *file_strm = NULL; - int start = 0, length = 0, read_len = 0; - char *metadata_file = crm_strdup_printf("%s/%s.xml", - NAGIOS_METADATA_DIR, type); - - file_strm = fopen(metadata_file, "r"); - if (file_strm == NULL) { - crm_err("Metadata file %s does not exist", metadata_file); - free(metadata_file); - return -EIO; - } - - /* see how big the file is */ - start = ftell(file_strm); - fseek(file_strm, 0L, SEEK_END); - length = ftell(file_strm); - fseek(file_strm, 0L, start); - - CRM_ASSERT(length >= 0); - CRM_ASSERT(start == ftell(file_strm)); - - if (length <= 0) { - crm_info("%s was not valid", metadata_file); - free(*output); - *output = NULL; - rc = -EIO; - - } else { - crm_trace("Reading %d bytes from file", length); - *output = calloc(1, (length + 1)); - read_len = fread(*output, 1, length, file_strm); - if (read_len != length) { - crm_err("Calculated and read bytes differ: %d vs. %d", - length, read_len); - free(*output); - *output = NULL; - rc = -EIO; - } - } - - fclose(file_strm); - free(metadata_file); - return rc; -} -#endif - static gboolean action_get_metadata(svc_action_t *op) { @@ -908,7 +863,7 @@ action_get_metadata(svc_action_t *op) #if SUPPORT_NAGIOS if (safe_str_eq(class, PCMK_RESOURCE_CLASS_NAGIOS)) { - return (nagios_get_metadata(op->agent, &op->stdout_data) >= 0); + return services__get_nagios_metadata(op->agent, &op->stdout_data) >= 0; } #endif @@ -985,7 +940,7 @@ resources_list_standards(void) #endif #if SUPPORT_NAGIOS - agents = resources_os_list_nagios_agents(); + agents = services__list_nagios_agents(); if (agents) { standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_NAGIOS)); @@ -1055,7 +1010,7 @@ resources_list_agents(const char *standard, const char *provider) #endif #if SUPPORT_NAGIOS } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_NAGIOS) == 0) { - return resources_os_list_nagios_agents(); + return services__list_nagios_agents(); #endif } diff --git a/lib/services/services_linux.c b/lib/services/services_linux.c index 1fb294c24c8..7f42bd4e42b 100644 --- a/lib/services/services_linux.c +++ b/lib/services/services_linux.c @@ -1,5 +1,7 @@ /* - * Copyright 2010-2019 Andrew Beekhof + * Copyright 2010-2019 the Pacemaker project contributors + * + * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. @@ -22,10 +24,6 @@ #include #include -#ifdef HAVE_SYS_SIGNALFD_H -#include -#endif - #include "crm/crm.h" #include "crm/common/mainloop.h" #include "crm/services.h" @@ -36,6 +34,228 @@ # include "crm/common/cib_secrets.h" #endif +static void close_pipe(int fildes[]); + +/* We have two alternative ways of handling SIGCHLD when synchronously waiting + * for spawned processes to complete. Both rely on polling a file descriptor to + * discover SIGCHLD events. + * + * If sys/signalfd.h is available (e.g. on Linux), we call signalfd() to + * generate the file descriptor. Otherwise, we use the "self-pipe trick" + * (opening a pipe and writing a byte to it when SIGCHLD is received). + */ +#ifdef HAVE_SYS_SIGNALFD_H + +// signalfd() implementation + +#include + +// Everything needed to manage SIGCHLD handling +struct sigchld_data_s { + sigset_t mask; // Signals to block now (including SIGCHLD) + sigset_t old_mask; // Previous set of blocked signals +}; + +// Initialize SIGCHLD data and prepare for use +static bool +sigchld_setup(struct sigchld_data_s *data) +{ + sigemptyset(&(data->mask)); + sigaddset(&(data->mask), SIGCHLD); + + sigemptyset(&(data->old_mask)); + + // Block SIGCHLD (saving previous set of blocked signals to restore later) + if (sigprocmask(SIG_BLOCK, &(data->mask), &(data->old_mask)) < 0) { + crm_err("Wait for child process completion failed: %s " + CRM_XS " source=sigprocmask", pcmk_strerror(errno)); + return false; + } + return true; +} + +// Get a file descriptor suitable for polling for SIGCHLD events +static int +sigchld_open(struct sigchld_data_s *data) +{ + int fd; + + CRM_CHECK(data != NULL, return -1); + + fd = signalfd(-1, &(data->mask), SFD_NONBLOCK); + if (fd < 0) { + crm_err("Wait for child process completion failed: %s " + CRM_XS " source=signalfd", pcmk_strerror(errno)); + } + return fd; +} + +// Close a file descriptor returned by sigchld_open() +static void +sigchld_close(int fd) +{ + if (fd > 0) { + close(fd); + } +} + +// Return true if SIGCHLD was received from polled fd +static bool +sigchld_received(int fd) +{ + struct signalfd_siginfo fdsi; + ssize_t s; + + if (fd < 0) { + return false; + } + s = read(fd, &fdsi, sizeof(struct signalfd_siginfo)); + if (s != sizeof(struct signalfd_siginfo)) { + crm_err("Wait for child process completion failed: %s " + CRM_XS " source=read", pcmk_strerror(errno)); + + } else if (fdsi.ssi_signo == SIGCHLD) { + return true; + } + return false; +} + +// Do anything needed after done waiting for SIGCHLD +static void +sigchld_cleanup(struct sigchld_data_s *data) +{ + // Restore the original set of blocked signals + if ((sigismember(&(data->old_mask), SIGCHLD) == 0) + && (sigprocmask(SIG_UNBLOCK, &(data->mask), NULL) < 0)) { + crm_warn("Could not clean up after child process completion: %s", + pcmk_strerror(errno)); + } +} + +#else // HAVE_SYS_SIGNALFD_H not defined + +// Self-pipe implementation (see above for function descriptions) + +struct sigchld_data_s { + int pipe_fd[2]; // Pipe file descriptors + struct sigaction sa; // Signal handling info (with SIGCHLD) + struct sigaction old_sa; // Previous signal handling info +}; + +// We need a global to use in the signal handler +volatile struct sigchld_data_s *last_sigchld_data = NULL; + +static void +sigchld_handler() +{ + // We received a SIGCHLD, so trigger pipe polling + if ((last_sigchld_data != NULL) + && (last_sigchld_data->pipe_fd[1] >= 0) + && (write(last_sigchld_data->pipe_fd[1], "", 1) == -1)) { + crm_err("Wait for child process completion failed: %s " + CRM_XS " source=write", pcmk_strerror(errno)); + } +} + +static bool +sigchld_setup(struct sigchld_data_s *data) +{ + int rc; + + data->pipe_fd[0] = data->pipe_fd[1] = -1; + + if (pipe(data->pipe_fd) == -1) { + crm_err("Wait for child process completion failed: %s " + CRM_XS " source=pipe", pcmk_strerror(errno)); + return false; + } + + rc = crm_set_nonblocking(data->pipe_fd[0]); + if (rc < 0) { + crm_warn("Could not set pipe input non-blocking: %s " CRM_XS " rc=%d", + pcmk_strerror(rc), rc); + } + rc = crm_set_nonblocking(data->pipe_fd[1]); + if (rc < 0) { + crm_warn("Could not set pipe output non-blocking: %s " CRM_XS " rc=%d", + pcmk_strerror(rc), rc); + } + + // Set SIGCHLD handler + data->sa.sa_handler = sigchld_handler; + data->sa.sa_flags = 0; + sigemptyset(&(data->sa.sa_mask)); + if (sigaction(SIGCHLD, &(data->sa), &(data->old_sa)) < 0) { + crm_err("Wait for child process completion failed: %s " + CRM_XS " source=sigaction", pcmk_strerror(errno)); + } + + // Remember data for use in signal handler + last_sigchld_data = data; + return true; +} + +static int +sigchld_open(struct sigchld_data_s *data) +{ + CRM_CHECK(data != NULL, return -1); + return data->pipe_fd[0]; +} + +static void +sigchld_close(int fd) +{ + // Pipe will be closed in sigchld_cleanup() + return; +} + +static bool +sigchld_received(int fd) +{ + char ch; + + if (fd < 0) { + return false; + } + + // Clear out the self-pipe + while (read(fd, &ch, 1) == 1) /*omit*/; + return true; +} + +static void +sigchld_cleanup(struct sigchld_data_s *data) +{ + // Restore the previous SIGCHLD handler + if (sigaction(SIGCHLD, &(data->old_sa), NULL) < 0) { + crm_warn("Could not clean up after child process completion: %s", + pcmk_strerror(errno)); + } + + close_pipe(data->pipe_fd); +} + +#endif + +/*! + * \internal + * \brief Close the two file descriptors of a pipe + * + * \param[in] fildes Array of file descriptors opened by pipe() + */ +static void +close_pipe(int fildes[]) +{ + if (fildes[0] >= 0) { + close(fildes[0]); + fildes[0] = -1; + } + if (fildes[1] >= 0) { + close(fildes[1]); + fildes[1] = -1; + } +} + static gboolean svc_read_output(int fd, svc_action_t * op, bool is_stderr) { @@ -313,76 +533,96 @@ operation_finalize(svc_action_t * op) } static void -operation_finished(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode) +close_op_input(svc_action_t *op) { - svc_action_t *op = mainloop_child_userdata(p); - char *prefix = crm_strdup_printf("%s:%d", op->id, op->pid); + if (op->opaque->stdin_fd >= 0) { + close(op->opaque->stdin_fd); + } +} - mainloop_clear_child_userdata(p); - op->status = PCMK_LRM_OP_DONE; - CRM_ASSERT(op->pid == pid); +static void +finish_op_output(svc_action_t *op, bool is_stderr) +{ + mainloop_io_t **source; + int fd; - crm_trace("%s %p %p", prefix, op->opaque->stderr_gsource, op->opaque->stdout_gsource); - if (op->opaque->stderr_gsource) { - /* Make sure we have read everything from the buffer. - * Depending on the priority mainloop gives the fd, operation_finished - * could occur before all the reads are done. Force the read now.*/ - crm_trace("%s dispatching stderr", prefix); - dispatch_stderr(op); - crm_trace("%s: %p", op->id, op->stderr_data); - mainloop_del_fd(op->opaque->stderr_gsource); - op->opaque->stderr_gsource = NULL; + if (is_stderr) { + source = &(op->opaque->stderr_gsource); + fd = op->opaque->stderr_fd; + } else { + source = &(op->opaque->stdout_gsource); + fd = op->opaque->stdout_fd; } - if (op->opaque->stdout_gsource) { - /* Make sure we have read everything from the buffer. - * Depending on the priority mainloop gives the fd, operation_finished - * could occur before all the reads are done. Force the read now.*/ - crm_trace("%s dispatching stdout", prefix); - dispatch_stdout(op); - crm_trace("%s: %p", op->id, op->stdout_data); - mainloop_del_fd(op->opaque->stdout_gsource); - op->opaque->stdout_gsource = NULL; + if (op->synchronous || *source) { + crm_trace("Finish reading %s[%d] %s", + op->id, op->pid, (is_stderr? "stdout" : "stderr")); + svc_read_output(fd, op, is_stderr); + if (op->synchronous) { + close(fd); + } else { + mainloop_del_fd(*source); + *source = NULL; + } } +} - if (op->opaque->stdin_fd >= 0) { - close(op->opaque->stdin_fd); - } +// Log an operation's stdout and stderr +static void +log_op_output(svc_action_t *op) +{ + char *prefix = crm_strdup_printf("%s[%d] error output", op->id, op->pid); - if (signo) { - if (mainloop_child_timeout(p)) { - crm_warn("%s - timed out after %dms", prefix, op->timeout); - op->status = PCMK_LRM_OP_TIMEOUT; - op->rc = PCMK_OCF_TIMEOUT; + crm_log_output(LOG_NOTICE, prefix, op->stderr_data); + strcpy(prefix + strlen(prefix) - strlen("error output"), "output"); + crm_log_output(LOG_DEBUG, prefix, op->stdout_data); + free(prefix); +} - } else if (op->cancel) { - /* If an in-flight recurring operation was killed because it was - * cancelled, don't treat that as a failure. - */ - crm_info("%s - terminated with signal %d", prefix, signo); - op->status = PCMK_LRM_OP_CANCELLED; - op->rc = PCMK_OCF_OK; +static void +operation_finished(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode) +{ + svc_action_t *op = mainloop_child_userdata(p); - } else { - crm_warn("%s - terminated with signal %d", prefix, signo); - op->status = PCMK_LRM_OP_ERROR; - op->rc = PCMK_OCF_SIGNAL; - } + mainloop_clear_child_userdata(p); + CRM_ASSERT(op->pid == pid); - } else { + /* Depending on the priority the mainloop gives the stdout and stderr + * file descriptors, this function could be called before everything has + * been read from them, so force a final read now. + */ + finish_op_output(op, true); + finish_op_output(op, false); + + close_op_input(op); + + if (signo == 0) { + crm_debug("%s[%d] exited with status %d", op->id, op->pid, exitcode); + op->status = PCMK_LRM_OP_DONE; op->rc = exitcode; - crm_debug("%s - exited with rc=%d", prefix, exitcode); - } - free(prefix); - prefix = crm_strdup_printf("%s:%d:stderr", op->id, op->pid); - crm_log_output(LOG_NOTICE, prefix, op->stderr_data); + } else if (mainloop_child_timeout(p)) { + crm_warn("%s[%d] timed out after %dms", op->id, op->pid, op->timeout); + op->status = PCMK_LRM_OP_TIMEOUT; + op->rc = PCMK_OCF_TIMEOUT; - free(prefix); - prefix = crm_strdup_printf("%s:%d:stdout", op->id, op->pid); - crm_log_output(LOG_DEBUG, prefix, op->stdout_data); + } else if (op->cancel) { + /* If an in-flight recurring operation was killed because it was + * cancelled, don't treat that as a failure. + */ + crm_info("%s[%d] terminated with signal: %s " CRM_XS " (%d)", + op->id, op->pid, strsignal(signo), signo); + op->status = PCMK_LRM_OP_CANCELLED; + op->rc = PCMK_OCF_OK; - free(prefix); + } else { + crm_warn("%s[%d] terminated with signal: %s " CRM_XS " (%d)", + op->id, op->pid, strsignal(signo), signo); + op->status = PCMK_LRM_OP_ERROR; + op->rc = PCMK_OCF_SIGNAL; + } + + log_op_output(op); operation_finalize(op); } @@ -524,40 +764,15 @@ action_launch_child(svc_action_t *op) _exit(op->rc); } -#ifndef HAVE_SYS_SIGNALFD_H -static int sigchld_pipe[2] = { -1, -1 }; - -static void -sigchld_handler() -{ - if ((sigchld_pipe[1] >= 0) && (write(sigchld_pipe[1], "", 1) == -1)) { - crm_perror(LOG_TRACE, "Could not poke SIGCHLD self-pipe"); - } -} -#endif - static void -action_synced_wait(svc_action_t * op, sigset_t *mask) +action_synced_wait(svc_action_t *op, struct sigchld_data_s *data) { int status = 0; int timeout = op->timeout; - int sfd = -1; time_t start = -1; struct pollfd fds[3]; int wait_rc = 0; -#ifdef HAVE_SYS_SIGNALFD_H - // mask is always non-NULL in practice, but this makes static analysis happy - if (mask) { - sfd = signalfd(-1, mask, SFD_NONBLOCK); - if (sfd < 0) { - crm_perror(LOG_ERR, "signalfd() failed"); - } - } -#else - sfd = sigchld_pipe[0]; -#endif - fds[0].fd = op->opaque->stdout_fd; fds[0].events = POLLIN; fds[0].revents = 0; @@ -566,11 +781,11 @@ action_synced_wait(svc_action_t * op, sigset_t *mask) fds[1].events = POLLIN; fds[1].revents = 0; - fds[2].fd = sfd; + fds[2].fd = sigchld_open(data); fds[2].events = POLLIN; fds[2].revents = 0; - crm_trace("Waiting for %d", op->pid); + crm_trace("Waiting for %s[%d]", op->id, op->pid); start = time(NULL); do { int poll_rc = poll(fds, 3, timeout); @@ -584,63 +799,45 @@ action_synced_wait(svc_action_t * op, sigset_t *mask) svc_read_output(op->opaque->stderr_fd, op, TRUE); } - if (fds[2].revents & POLLIN) { -#ifdef HAVE_SYS_SIGNALFD_H - struct signalfd_siginfo fdsi; - ssize_t s; - - s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo)); - if (s != sizeof(struct signalfd_siginfo)) { - crm_perror(LOG_ERR, "Read from signal fd %d failed", sfd); - - } else if (fdsi.ssi_signo == SIGCHLD) { -#else - if (1) { - /* Clear out the sigchld pipe. */ - char ch; - while (read(sfd, &ch, 1) == 1) /*omit*/; -#endif - wait_rc = waitpid(op->pid, &status, WNOHANG); - - if (wait_rc > 0) { - break; - - } else if (wait_rc < 0){ - if (errno == ECHILD) { - /* Here, don't dare to kill and bail out... */ - break; - - } else { - /* ...otherwise pretend process still runs. */ - wait_rc = 0; - } - crm_perror(LOG_ERR, "waitpid() for %d failed", op->pid); - } + if ((fds[2].revents & POLLIN) && sigchld_received(fds[2].fd)) { + wait_rc = waitpid(op->pid, &status, WNOHANG); + + if ((wait_rc > 0) || ((wait_rc < 0) && (errno == ECHILD))) { + // Child process exited or doesn't exist + break; + + } else if (wait_rc < 0) { + crm_warn("Wait for completion of %s[%d] failed: %s " + CRM_XS " source=waitpid", + op->id, op->pid, pcmk_strerror(errno)); + wait_rc = 0; // Act as if process is still running } } } else if (poll_rc == 0) { + // Poll timed out with no descriptors ready timeout = 0; break; - } else if (poll_rc < 0) { - if (errno != EINTR) { - crm_perror(LOG_ERR, "poll() failed"); - break; - } + } else if ((poll_rc < 0) && (errno != EINTR)) { + crm_err("Wait for completion of %s[%d] failed: %s " + CRM_XS " source=poll", + op->id, op->pid, pcmk_strerror(errno)); + break; } timeout = op->timeout - (time(NULL) - start) * 1000; } while ((op->timeout < 0 || timeout > 0)); - crm_trace("Child done: %d", op->pid); + crm_trace("Stopped waiting for %s[%d]", op->id, op->pid); if (wait_rc <= 0) { op->rc = PCMK_OCF_UNKNOWN_ERROR; if (op->timeout > 0 && timeout <= 0) { op->status = PCMK_LRM_OP_TIMEOUT; - crm_warn("%s:%d - timed out after %dms", op->id, op->pid, op->timeout); + crm_warn("%s[%d] timed out after %dms", + op->id, op->pid, op->timeout); } else { op->status = PCMK_LRM_OP_ERROR; @@ -650,7 +847,8 @@ action_synced_wait(svc_action_t * op, sigset_t *mask) This is to limit killing wrong target a bit more. */ if (wait_rc == 0 && waitpid(op->pid, &status, WNOHANG) == 0) { if (kill(op->pid, SIGKILL)) { - crm_err("kill(%d, KILL) failed: %d", op->pid, errno); + crm_warn("Could not kill rogue child %s[%d]: %s", + op->id, op->pid, pcmk_strerror(errno)); } /* Safe to skip WNOHANG here as we sent non-ignorable signal. */ while (waitpid(op->pid, &status, 0) == (pid_t) -1 && errno == EINTR) /*omit*/; @@ -659,32 +857,25 @@ action_synced_wait(svc_action_t * op, sigset_t *mask) } else if (WIFEXITED(status)) { op->status = PCMK_LRM_OP_DONE; op->rc = WEXITSTATUS(status); - crm_info("Managed %s process %d exited with rc=%d", op->id, op->pid, op->rc); + crm_info("%s[%d] exited with status %d", op->id, op->pid, op->rc); } else if (WIFSIGNALED(status)) { int signo = WTERMSIG(status); op->status = PCMK_LRM_OP_ERROR; - crm_err("Managed %s process %d exited with signal=%d", op->id, op->pid, signo); + crm_err("%s[%d] terminated with signal: %s " CRM_XS " (%d)", + op->id, op->pid, strsignal(signo), signo); } #ifdef WCOREDUMP if (WCOREDUMP(status)) { - crm_err("Managed %s process %d dumped core", op->id, op->pid); + crm_err("%s[%d] dumped core", op->id, op->pid); } #endif - svc_read_output(op->opaque->stdout_fd, op, FALSE); - svc_read_output(op->opaque->stderr_fd, op, TRUE); - - close(op->opaque->stdout_fd); - close(op->opaque->stderr_fd); - if (op->opaque->stdin_fd >= 0) { - close(op->opaque->stdin_fd); - } - -#ifdef HAVE_SYS_SIGNALFD_H - close(sfd); -#endif + finish_op_output(op, true); + finish_op_output(op, false); + close_op_input(op); + sigchld_close(fds[2].fd); } /* For an asynchronous 'op', returns FALSE if 'op' should be free'd by the caller */ @@ -697,35 +888,13 @@ services_os_action_execute(svc_action_t * op) int stdin_fd[2] = {-1, -1}; int rc; struct stat st; - sigset_t *pmask = NULL; - -#ifdef HAVE_SYS_SIGNALFD_H - sigset_t mask; - sigset_t old_mask; -#define sigchld_cleanup() do { \ - if (sigismember(&old_mask, SIGCHLD) == 0) { \ - if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0) { \ - crm_perror(LOG_ERR, "sigprocmask() failed to unblock sigchld"); \ - } \ - } \ -} while (0) -#else - struct sigaction sa; - struct sigaction old_sa; -#define sigchld_cleanup() do { \ - if (sigaction(SIGCHLD, &old_sa, NULL) < 0) { \ - crm_perror(LOG_ERR, "sigaction() failed to remove sigchld handler"); \ - } \ - close(sigchld_pipe[0]); \ - close(sigchld_pipe[1]); \ - sigchld_pipe[0] = sigchld_pipe[1] = -1; \ -} while(0) -#endif + struct sigchld_data_s data; /* Fail fast */ if(stat(op->opaque->exec, &st) != 0) { rc = errno; - crm_warn("Cannot execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc); + crm_warn("Cannot execute '%s': %s " CRM_XS " stat rc=%d", + op->opaque->exec, pcmk_strerror(rc), rc); services_handle_exec_error(op, rc); if (!op->synchronous) { return operation_finalize(op); @@ -735,9 +904,8 @@ services_os_action_execute(svc_action_t * op) if (pipe(stdout_fd) < 0) { rc = errno; - - crm_err("pipe(stdout_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc); - + crm_err("Cannot execute '%s': %s " CRM_XS " pipe(stdout) rc=%d", + op->opaque->exec, pcmk_strerror(rc), rc); services_handle_exec_error(op, rc); if (!op->synchronous) { return operation_finalize(op); @@ -748,11 +916,10 @@ services_os_action_execute(svc_action_t * op) if (pipe(stderr_fd) < 0) { rc = errno; - close(stdout_fd[0]); - close(stdout_fd[1]); - - crm_err("pipe(stderr_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc); + close_pipe(stdout_fd); + crm_err("Cannot execute '%s': %s " CRM_XS " pipe(stderr) rc=%d", + op->opaque->exec, pcmk_strerror(rc), rc); services_handle_exec_error(op, rc); if (!op->synchronous) { return operation_finalize(op); @@ -764,13 +931,11 @@ services_os_action_execute(svc_action_t * op) if (pipe(stdin_fd) < 0) { rc = errno; - close(stdout_fd[0]); - close(stdout_fd[1]); - close(stderr_fd[0]); - close(stderr_fd[1]); - - crm_err("pipe(stdin_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc); + close_pipe(stdout_fd); + close_pipe(stderr_fd); + crm_err("Cannot execute '%s': %s " CRM_XS " pipe(stdin) rc=%d", + op->opaque->exec, pcmk_strerror(rc), rc); services_handle_exec_error(op, rc); if (!op->synchronous) { return operation_finalize(op); @@ -779,65 +944,30 @@ services_os_action_execute(svc_action_t * op) } } - if (op->synchronous) { -#ifdef HAVE_SYS_SIGNALFD_H - sigemptyset(&mask); - sigaddset(&mask, SIGCHLD); - sigemptyset(&old_mask); - - if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) { - crm_perror(LOG_ERR, "sigprocmask() failed to block sigchld"); - } - - pmask = &mask; -#else - if(pipe(sigchld_pipe) == -1) { - crm_perror(LOG_ERR, "pipe() failed"); - } - - rc = crm_set_nonblocking(sigchld_pipe[0]); - if (rc < 0) { - crm_warn("Could not set pipe input non-blocking: %s " CRM_XS " rc=%d", - pcmk_strerror(rc), rc); - } - rc = crm_set_nonblocking(sigchld_pipe[1]); - if (rc < 0) { - crm_warn("Could not set pipe output non-blocking: %s " CRM_XS " rc=%d", - pcmk_strerror(rc), rc); - } - - sa.sa_handler = sigchld_handler; - sa.sa_flags = 0; - sigemptyset(&sa.sa_mask); - if (sigaction(SIGCHLD, &sa, &old_sa) < 0) { - crm_perror(LOG_ERR, "sigaction() failed to set sigchld handler"); - } - - pmask = NULL; -#endif + if (op->synchronous && !sigchld_setup(&data)) { + close_pipe(stdin_fd); + close_pipe(stdout_fd); + close_pipe(stderr_fd); + sigchld_cleanup(&data); + return FALSE; } op->pid = fork(); switch (op->pid) { case -1: rc = errno; + close_pipe(stdin_fd); + close_pipe(stdout_fd); + close_pipe(stderr_fd); - close(stdout_fd[0]); - close(stdout_fd[1]); - close(stderr_fd[0]); - close(stderr_fd[1]); - if (stdin_fd[0] >= 0) { - close(stdin_fd[0]); - close(stdin_fd[1]); - } - - crm_err("Could not execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc); + crm_err("Cannot execute '%s': %s " CRM_XS " fork rc=%d", + op->opaque->exec, pcmk_strerror(rc), rc); services_handle_exec_error(op, rc); if (!op->synchronous) { return operation_finalize(op); } - sigchld_cleanup(); + sigchld_cleanup(&data); return FALSE; case 0: /* Child */ @@ -848,26 +978,32 @@ services_os_action_execute(svc_action_t * op) } if (STDOUT_FILENO != stdout_fd[1]) { if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) { - crm_err("dup2() failed (stdout)"); + crm_warn("Can't redirect output from '%s': %s " + CRM_XS " errno=%d", + op->opaque->exec, pcmk_strerror(errno), errno); } close(stdout_fd[1]); } if (STDERR_FILENO != stderr_fd[1]) { if (dup2(stderr_fd[1], STDERR_FILENO) != STDERR_FILENO) { - crm_err("dup2() failed (stderr)"); + crm_warn("Can't redirect error output from '%s': %s " + CRM_XS " errno=%d", + op->opaque->exec, pcmk_strerror(errno), errno); } close(stderr_fd[1]); } if ((stdin_fd[0] >= 0) && (STDIN_FILENO != stdin_fd[0])) { if (dup2(stdin_fd[0], STDIN_FILENO) != STDIN_FILENO) { - crm_err("dup2() failed (stdin)"); + crm_warn("Can't redirect input to '%s': %s " + CRM_XS " errno=%d", + op->opaque->exec, pcmk_strerror(errno), errno); } close(stdin_fd[0]); } if (op->synchronous) { - sigchld_cleanup(); + sigchld_cleanup(&data); } action_launch_child(op); @@ -884,17 +1020,17 @@ services_os_action_execute(svc_action_t * op) op->opaque->stdout_fd = stdout_fd[0]; rc = crm_set_nonblocking(op->opaque->stdout_fd); if (rc < 0) { - crm_warn("Could not set child output non-blocking: %s " + crm_warn("Could not set '%s' output non-blocking: %s " CRM_XS " rc=%d", - pcmk_strerror(rc), rc); + op->opaque->exec, pcmk_strerror(rc), rc); } op->opaque->stderr_fd = stderr_fd[0]; rc = crm_set_nonblocking(op->opaque->stderr_fd); if (rc < 0) { - crm_warn("Could not set child error output non-blocking: %s " + crm_warn("Could not set '%s' error output non-blocking: %s " CRM_XS " rc=%d", - pcmk_strerror(rc), rc); + op->opaque->exec, pcmk_strerror(rc), rc); } op->opaque->stdin_fd = stdin_fd[1]; @@ -903,8 +1039,8 @@ services_os_action_execute(svc_action_t * op) // as long as no other standard uses stdin_fd assume stonith rc = crm_set_nonblocking(op->opaque->stdin_fd); if (rc < 0) { - crm_warn("Could not set child input non-blocking: %s " - CRM_XS " fd=%d,rc=%d", + crm_warn("Could not set '%s' input non-blocking: %s " + CRM_XS " fd=%d,rc=%d", op->opaque->exec, pcmk_strerror(rc), op->opaque->stdin_fd, rc); } pipe_in_action_stdin_parameters(op); @@ -919,11 +1055,10 @@ services_os_action_execute(svc_action_t * op) } if (op->synchronous) { - action_synced_wait(op, pmask); - sigchld_cleanup(); + action_synced_wait(op, &data); + sigchld_cleanup(&data); } else { - - crm_trace("Async waiting for %d - %s", op->pid, op->opaque->exec); + crm_trace("Waiting async for '%s'[%d]", op->opaque->exec, op->pid); mainloop_child_add_with_flags(op->pid, op->timeout, op->id, @@ -1053,50 +1188,3 @@ services__ocf_agent_exists(const char *provider, const char *agent) free(buf); return rc; } - -#if SUPPORT_NAGIOS -GList * -resources_os_list_nagios_agents(void) -{ - GList *plugin_list = NULL; - GList *result = NULL; - GList *gIter = NULL; - - plugin_list = get_directory_list(NAGIOS_PLUGIN_DIR, TRUE, TRUE); - - /* Make sure both the plugin and its metadata exist */ - for (gIter = plugin_list; gIter != NULL; gIter = gIter->next) { - const char *plugin = gIter->data; - char *metadata = crm_strdup_printf(NAGIOS_METADATA_DIR "/%s.xml", plugin); - struct stat st; - - if (stat(metadata, &st) == 0) { - result = g_list_append(result, strdup(plugin)); - } - - free(metadata); - } - g_list_free_full(plugin_list, free); - return result; -} - -gboolean -services__nagios_agent_exists(const char *name) -{ - char *buf = NULL; - gboolean rc = FALSE; - struct stat st; - - if (name == NULL) { - return rc; - } - - buf = crm_strdup_printf(NAGIOS_PLUGIN_DIR "/%s", name); - if (stat(buf, &st) == 0) { - rc = TRUE; - } - - free(buf); - return rc; -} -#endif diff --git a/lib/services/services_nagios.c b/lib/services/services_nagios.c new file mode 100644 index 00000000000..2e1817c3d11 --- /dev/null +++ b/lib/services/services_nagios.c @@ -0,0 +1,129 @@ +/* + * Copyright 2010-2019 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU Lesser General Public License + * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. + */ + +#include + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "crm/crm.h" +#include "crm/common/mainloop.h" +#include "crm/services.h" + +#include "services_private.h" +#include "services_nagios.h" + +static inline char * +nagios_metadata_name(const char *plugin) +{ + return crm_strdup_printf(NAGIOS_METADATA_DIR "/%s.xml", plugin); +} + +GList * +services__list_nagios_agents(void) +{ + GList *plugin_list = NULL; + GList *result = NULL; + + plugin_list = services_os_get_directory_list(NAGIOS_PLUGIN_DIR, TRUE, TRUE); + + // Return only the plugins that have metadata + for (GList *gIter = plugin_list; gIter != NULL; gIter = gIter->next) { + struct stat st; + const char *plugin = gIter->data; + char *metadata = nagios_metadata_name(plugin); + + if (stat(metadata, &st) == 0) { + result = g_list_append(result, strdup(plugin)); + } + free(metadata); + } + g_list_free_full(plugin_list, free); + return result; +} + +gboolean +services__nagios_agent_exists(const char *name) +{ + char *buf = NULL; + gboolean rc = FALSE; + struct stat st; + + if (name == NULL) { + return rc; + } + + buf = crm_strdup_printf(NAGIOS_PLUGIN_DIR "/%s", name); + if (stat(buf, &st) == 0) { + rc = TRUE; + } + + free(buf); + return rc; +} + +int +services__get_nagios_metadata(const char *type, char **output) +{ + int rc = pcmk_ok; + FILE *file_strm = NULL; + int start = 0, length = 0, read_len = 0; + char *metadata_file = nagios_metadata_name(type); + + file_strm = fopen(metadata_file, "r"); + if (file_strm == NULL) { + crm_err("Metadata file %s does not exist", metadata_file); + free(metadata_file); + return -EIO; + } + + /* see how big the file is */ + start = ftell(file_strm); + fseek(file_strm, 0L, SEEK_END); + length = ftell(file_strm); + fseek(file_strm, 0L, start); + + CRM_ASSERT(length >= 0); + CRM_ASSERT(start == ftell(file_strm)); + + if (length <= 0) { + crm_info("%s was not valid", metadata_file); + free(*output); + *output = NULL; + rc = -EIO; + + } else { + crm_trace("Reading %d bytes from file", length); + *output = calloc(1, (length + 1)); + read_len = fread(*output, 1, length, file_strm); + if (read_len != length) { + crm_err("Calculated and read bytes differ: %d vs. %d", + length, read_len); + free(*output); + *output = NULL; + rc = -EIO; + } + } + + fclose(file_strm); + free(metadata_file); + return rc; +} diff --git a/lib/services/services_nagios.h b/lib/services/services_nagios.h new file mode 100644 index 00000000000..1afd7640496 --- /dev/null +++ b/lib/services/services_nagios.h @@ -0,0 +1,22 @@ +/* + * Copyright 2010-2019 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU Lesser General Public License + * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. + */ + +#ifndef SERVICES_NAGIOS__H +# define SERVICES_NAGIOS__H + +G_GNUC_INTERNAL +GList *services__list_nagios_agents(void); + +G_GNUC_INTERNAL +gboolean services__nagios_agent_exists(const char *agent); + +G_GNUC_INTERNAL +int services__get_nagios_metadata(const char *type, char **output); + +#endif diff --git a/lib/services/services_private.h b/lib/services/services_private.h index 660a35b6729..f669ce4925e 100644 --- a/lib/services/services_private.h +++ b/lib/services/services_private.h @@ -55,12 +55,6 @@ GList *resources_os_list_ocf_agents(const char *provider); G_GNUC_INTERNAL gboolean services__ocf_agent_exists(const char *provider, const char *agent); -G_GNUC_INTERNAL -GList *resources_os_list_nagios_agents(void); - -G_GNUC_INTERNAL -gboolean services__nagios_agent_exists(const char *agent); - G_GNUC_INTERNAL gboolean cancel_recurring_action(svc_action_t * op); diff --git a/tools/cibadmin.c b/tools/cibadmin.c index 1f33e9fe8bc..9661320c94d 100644 --- a/tools/cibadmin.c +++ b/tools/cibadmin.c @@ -184,7 +184,6 @@ main(int argc, char **argv) int option_index = 0; - crm_xml_init(); /* Sets buffer allocation strategy */ crm_log_cli_init("cibadmin"); set_crm_log_level(LOG_CRIT); crm_set_options(NULL, "command [options] [data]", long_options, diff --git a/tools/crm_shadow.c b/tools/crm_shadow.c index 9821c47e06b..9171b5e50ce 100644 --- a/tools/crm_shadow.c +++ b/tools/crm_shadow.c @@ -417,7 +417,7 @@ main(int argc, char **argv) xml_accept_changes(new_config); if (diff != NULL) { - xml_log_patchset(0, " ", diff); + xml_log_patchset(LOG_STDOUT, " ", diff); exit_code = CRM_EX_ERROR; } goto done; diff --git a/tools/iso8601.c b/tools/iso8601.c index c442238d133..5e84faaa8ae 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -54,13 +54,9 @@ log_time_period(int log_level, crm_time_period_t * dtp, int flags) { char *start = crm_time_as_string(dtp->start, flags); char *end = crm_time_as_string(dtp->end, flags); - CRM_ASSERT(start != NULL && end != NULL); - if (log_level < LOG_CRIT) { - printf("Period: %s to %s\n", start, end); - } else { - do_crm_log(log_level, "Period: %s to %s", start, end); - } + CRM_ASSERT(start != NULL && end != NULL); + do_crm_log(log_level, "Period: %s to %s", start, end); free(start); free(end); } @@ -145,7 +141,7 @@ main(int argc, char **argv) } crm_time_log(LOG_TRACE, "Current date/time", date_time, crm_time_ordinal | crm_time_log_date | crm_time_log_timeofday); - crm_time_log(-1, "Current date/time", date_time, + crm_time_log(LOG_STDOUT, "Current date/time", date_time, print_options | crm_time_log_date | crm_time_log_timeofday); } else if (date_time_s) { @@ -157,7 +153,7 @@ main(int argc, char **argv) } crm_time_log(LOG_TRACE, "Date", date_time, crm_time_ordinal | crm_time_log_date | crm_time_log_timeofday); - crm_time_log(-1, "Date", date_time, + crm_time_log(LOG_STDOUT, "Date", date_time, print_options | crm_time_log_date | crm_time_log_timeofday); } @@ -169,7 +165,8 @@ main(int argc, char **argv) crm_exit(CRM_EX_INVALID_PARAM); } crm_time_log(LOG_TRACE, "Duration", duration, crm_time_log_duration); - crm_time_log(-1, "Duration", duration, print_options | crm_time_log_duration); + crm_time_log(LOG_STDOUT, "Duration", duration, + print_options | crm_time_log_duration); } if (period_s) { @@ -181,7 +178,7 @@ main(int argc, char **argv) } log_time_period(LOG_TRACE, period, print_options | crm_time_log_date | crm_time_log_timeofday); - log_time_period(-1, period, + log_time_period(LOG_STDOUT, period, print_options | crm_time_log_date | crm_time_log_timeofday); crm_time_free_period(period); } @@ -196,7 +193,7 @@ main(int argc, char **argv) } crm_time_log(LOG_TRACE, "Duration ends at", later, crm_time_ordinal | crm_time_log_date | crm_time_log_timeofday); - crm_time_log(-1, "Duration ends at", later, + crm_time_log(LOG_STDOUT, "Duration ends at", later, print_options | crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone); if (expected_s) {