The branch, master has been updated
via 7900f319db3 ctdb-server: Load optional tunables.d/ directory
via 598d9b4dfd4 ctdb-server: Whitespace fixes
via 6863799ce93 ctdb-tests: Add tests for tunables directory loading
via 4f1e3844b43 ctdb-common: Add tunable directory loading
via de069d6b950 ctdb-tests: Allow tunables unit test to process a
second file
via 4352a8da5ac ctdb-common: Log tunables filename instead of function
name
via cdb02782f95 ctdb-common: Log a message if the tunables file does
not exist
via 7d010715c59 ctdb-tests: Add logging support to the tunables unit
test
via 2ec739a039e ctdb-common: Require separate initialisation of tunable
defaults
via 96865764305 ctdb-tests: Reformat with "shfmt -w -p -i 0 -fn"
via c6f2664b489 ctdb-common: Fix includes to make file standalone
from b72cc7ce6ac libcli/smb: use talloc_asprintf_addbuf() in
smbXcli_session_dump_keys()
https://git.samba.org/?p=samba.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit 7900f319db3135000f71836dbe0279c616a6cf20
Author: Martin Schwenke <[email protected]>
Date: Wed Jun 25 22:18:16 2025 +1000
ctdb-server: Load optional tunables.d/ directory
Change the variable name to "path" so it makes sense to reuse it for
the directory.
Signed-off-by: Martin Schwenke <[email protected]>
Reviewed-by: Amitay Isaacs <[email protected]>
Autobuild-User(master): Martin Schwenke <[email protected]>
Autobuild-Date(master): Wed Jul 23 00:02:47 UTC 2025 on atb-devel-224
commit 598d9b4dfd47f1101f8d531b6f96d31c4194ff4b
Author: Martin Schwenke <[email protected]>
Date: Wed Jun 25 22:21:39 2025 +1000
ctdb-server: Whitespace fixes
Signed-off-by: Martin Schwenke <[email protected]>
Reviewed-by: Amitay Isaacs <[email protected]>
commit 6863799ce93b655f2f412f304b1556b9f09dd1a9
Author: Martin Schwenke <[email protected]>
Date: Fri Jun 27 17:35:03 2025 +1000
ctdb-tests: Add tests for tunables directory loading
The missing 2nd file testcase becomes the missing directory testcase,
because you can't easily have both. See the comment in
tunable_test.c.
Signed-off-by: Martin Schwenke <[email protected]>
Reviewed-by: Amitay Isaacs <[email protected]>
commit 4f1e3844b432dc2b72e62bf17cb4dd36f28d6380
Author: Martin Schwenke <[email protected]>
Date: Fri Jun 27 15:11:59 2025 +1000
ctdb-common: Add tunable directory loading
This is simpler than include files and more general than just allowing
a 2nd file to be loaded.
Signed-off-by: Martin Schwenke <[email protected]>
Reviewed-by: Amitay Isaacs <[email protected]>
commit de069d6b950531b3c2ad4584ae661980bd25a982
Author: Martin Schwenke <[email protected]>
Date: Wed Jun 25 22:14:05 2025 +1000
ctdb-tests: Allow tunables unit test to process a second file
The second file is optional.
Make $tfile the default to avoid having to update all of the single
file testcases.
Add test cases for second file.
Signed-off-by: Martin Schwenke <[email protected]>
Reviewed-by: Amitay Isaacs <[email protected]>
commit 4352a8da5ac05b8745b6197fa80774d8b0fe5f4b
Author: Martin Schwenke <[email protected]>
Date: Fri Jun 27 15:05:04 2025 +1000
ctdb-common: Log tunables filename instead of function name
When loading multiple files, this is more informative.
Tweak a couple of error messages to ensure they all mention
"tunables".
Update the unit testcases to match.
Signed-off-by: Martin Schwenke <[email protected]>
Reviewed-by: Amitay Isaacs <[email protected]>
commit cdb02782f950bf3a7585a8390a0c40ed81cd3971
Author: Martin Schwenke <[email protected]>
Date: Sun Jun 29 10:16:20 2025 +1000
ctdb-common: Log a message if the tunables file does not exist
Switch the unit test script to INFO debug level to ensure this output
appears when expected.
Signed-off-by: Martin Schwenke <[email protected]>
Reviewed-by: Amitay Isaacs <[email protected]>
commit 7d010715c591fc05871078958c08eb7207729c65
Author: Martin Schwenke <[email protected]>
Date: Sat Jun 28 12:01:41 2025 +1000
ctdb-tests: Add logging support to the tunables unit test
Make tunable_test respect CTDB_DEBUGLEVEL. Using test_options.[ch]
would be overkill here. This means including logging.c - we can't
link to the subsystem containing logging.c because the file being
tested (tunable.c) is part of that subsystem.
Support logging in the test script. tunable_ok() builds the logging
output for the good path. Set the debug level to NOTICE and update
expected results for individual failure path tests.
Signed-off-by: Martin Schwenke <[email protected]>
Reviewed-by: Amitay Isaacs <[email protected]>
commit 2ec739a039e3a9af82e614afeae54359fb05b288
Author: Martin Schwenke <[email protected]>
Date: Wed Jun 25 20:46:26 2025 +1000
ctdb-common: Require separate initialisation of tunable defaults
Dropping this from ctdb_tunable_load_file() allows that function to be
called multiple times for different files. The caller sets the
defaults.
In the test script, factor out the handling of a single tunables file
in a similar way. Ignoring missing/unreadable files is OK because
this function will only be called for test successes (hence "ok" in
the name). There will never be existing, unreadable files. The code
being tested ignores missing files, so do that here too.
Signed-off-by: Martin Schwenke <[email protected]>
Reviewed-by: Amitay Isaacs <[email protected]>
commit 968657643052a90bab1deb5ffd4938a256e5ee14
Author: Martin Schwenke <[email protected]>
Date: Sat Jun 28 12:12:33 2025 +1000
ctdb-tests: Reformat with "shfmt -w -p -i 0 -fn"
Best reviewed with "git show -w".
Signed-off-by: Martin Schwenke <[email protected]>
Reviewed-by: Amitay Isaacs <[email protected]>
commit c6f2664b489fd2eb0ce029fb3ab86fc77ca809f0
Author: Martin Schwenke <[email protected]>
Date: Wed Jun 25 20:44:52 2025 +1000
ctdb-common: Fix includes to make file standalone
Avoid lots of red underlines in my editor.
Signed-off-by: Martin Schwenke <[email protected]>
Reviewed-by: Amitay Isaacs <[email protected]>
-----------------------------------------------------------------------
Summary of changes:
ctdb/common/tunable.c | 100 ++++++++++--
ctdb/common/tunable.h | 10 ++
ctdb/doc/ctdb-tunables.7.xml | 15 +-
ctdb/server/ctdb_tunables.c | 42 +++--
ctdb/tests/UNIT/cunit/tunable_test_001.sh | 245 +++++++++++++++++++++++++-----
ctdb/tests/src/tunable_test.c | 54 ++++++-
6 files changed, 401 insertions(+), 65 deletions(-)
Changeset truncated at 500 lines:
diff --git a/ctdb/common/tunable.c b/ctdb/common/tunable.c
index f366f231e53..e7525f586b6 100644
--- a/ctdb/common/tunable.c
+++ b/ctdb/common/tunable.c
@@ -18,7 +18,9 @@
*/
#include "replace.h"
+#include "system/dir.h"
#include "system/filesys.h"
+#include "system/glob.h"
#include "system/locale.h"
#include "system/network.h"
@@ -289,7 +291,7 @@ char *ctdb_tunable_names_to_string(TALLOC_CTX *mem_ctx)
struct tunable_load_state {
struct ctdb_tunable_list *tun_list;
bool status;
- const char *func;
+ const char *file;
};
static bool tunable_section(const char *section, void *private_data)
@@ -297,8 +299,9 @@ static bool tunable_section(const char *section, void
*private_data)
struct tunable_load_state *state =
(struct tunable_load_state *)private_data;
- D_ERR("%s: Invalid line for section [%s] - sections not supported \n",
- state->func,
+ D_ERR("%s: Invalid line for section [%s] - "
+ "tunables sections not supported \n",
+ state->file,
section);
state->status = false;
@@ -317,7 +320,9 @@ static bool tunable_option(const char *name,
int ret;
if (value[0] == '\0') {
- D_ERR("%s: Invalid line containing \"%s\"\n", state->func,
name);
+ D_ERR("%s: Invalid tunables line containing \"%s\"\n",
+ state->file,
+ name);
state->status = false;
return true;
}
@@ -325,7 +330,7 @@ static bool tunable_option(const char *name,
num = smb_strtoul(value, NULL, 0, &ret, SMB_STR_FULL_STR_CONV);
if (ret != 0) {
D_ERR("%s: Invalid value \"%s\" for tunable \"%s\"\n",
- state->func,
+ state->file,
value,
name);
state->status = false;
@@ -337,12 +342,12 @@ static bool tunable_option(const char *name,
(uint32_t)num,
&obsolete);
if (!ok) {
- D_ERR("%s: Unknown tunable \"%s\"\n", state->func, name);
+ D_ERR("%s: Unknown tunable \"%s\"\n", state->file, name);
state->status = false;
return true;
}
if (obsolete) {
- D_ERR("%s: Obsolete tunable \"%s\"\n", state->func, name);
+ D_ERR("%s: Obsolete tunable \"%s\"\n", state->file, name);
state->status = false;
return true;
}
@@ -356,18 +361,16 @@ bool ctdb_tunable_load_file(TALLOC_CTX *mem_ctx,
{
struct tunable_load_state state = {
.tun_list = tun_list,
+ .file = file,
.status = true,
- .func = __FUNCTION__,
};
FILE *fp;
bool status;
- ctdb_tunable_set_defaults(tun_list);
-
fp = fopen(file, "r");
if (fp == NULL) {
if (errno == ENOENT) {
- /* Doesn't need to exist */
+ D_INFO("Optional tunables file %s not found\n", file);
return true;
}
@@ -394,8 +397,81 @@ bool ctdb_tunable_load_file(TALLOC_CTX *mem_ctx,
fclose(fp);
if (!status) {
- DBG_ERR("Syntax error\n");
+ D_ERR("%s: Syntax error\n", file);
}
return status && state.status;
}
+
+static int tunables_filter(const struct dirent *de)
+{
+ int ret;
+
+ /* Match a script pattern */
+ ret = fnmatch("*.tunables", de->d_name, 0);
+ if (ret == 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+bool ctdb_tunable_load_directory(TALLOC_CTX *mem_ctx,
+ struct ctdb_tunable_list *tun_list,
+ const char *dir)
+{
+ struct dirent **namelist = NULL;
+ int count = 0;
+ bool status = true;
+ int i = 0;
+
+ count = scandir(dir, &namelist, tunables_filter, alphasort);
+ if (count == -1) {
+ switch (errno) {
+ case ENOENT:
+ D_INFO("Optional tunables directory %s not found\n",
+ dir);
+ break;
+ default:
+ DBG_ERR("Failed to open directory %s (err=%d)\n",
+ dir,
+ errno);
+ status = false;
+ }
+ goto done;
+ }
+
+ if (count == 0) {
+ goto done;
+ }
+
+ for (i = 0; i < count; i++) {
+ char *file = NULL;
+ bool file_status = false;
+
+ file = talloc_asprintf(mem_ctx,
+ "%s/%s",
+ dir,
+ namelist[i]->d_name);
+ if (file == NULL) {
+ DBG_ERR("Memory allocation error\n");
+ goto done;
+ }
+
+ file_status = ctdb_tunable_load_file(mem_ctx, tun_list, file);
+ if (!file_status) {
+ status = false;
+ }
+ TALLOC_FREE(file);
+ }
+
+done:
+ if (namelist != NULL && count != -1) {
+ for (i = 0; i < count; i++) {
+ free(namelist[i]);
+ }
+ free(namelist);
+ }
+
+ return status;
+}
diff --git a/ctdb/common/tunable.h b/ctdb/common/tunable.h
index 89f99f1644f..bd8ee45bf1a 100644
--- a/ctdb/common/tunable.h
+++ b/ctdb/common/tunable.h
@@ -20,6 +20,13 @@
#ifndef __CTDB_TUNABLE_H__
#define __CTDB_TUNABLE_H__
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <talloc.h>
+
+#include "protocol/protocol.h"
+
void ctdb_tunable_set_defaults(struct ctdb_tunable_list *tun_list);
bool ctdb_tunable_get_value(struct ctdb_tunable_list *tun_list,
const char *tunable_str, uint32_t *value);
@@ -31,5 +38,8 @@ char *ctdb_tunable_names_to_string(TALLOC_CTX *mem_ctx);
bool ctdb_tunable_load_file(TALLOC_CTX *mem_ctx,
struct ctdb_tunable_list *tun_list,
const char *file);
+bool ctdb_tunable_load_directory(TALLOC_CTX *mem_ctx,
+ struct ctdb_tunable_list *tun_list,
+ const char *dir);
#endif /* __CTDB_TUNABLE_H__ */
diff --git a/ctdb/doc/ctdb-tunables.7.xml b/ctdb/doc/ctdb-tunables.7.xml
index 766213e1423..56b1e055a84 100644
--- a/ctdb/doc/ctdb-tunables.7.xml
+++ b/ctdb/doc/ctdb-tunables.7.xml
@@ -38,9 +38,17 @@
</para>
<para>
- Tunables can be set at startup from the
- <filename>/usr/local/etc/ctdb/ctdb.tunables</filename>
- configuration file.
+ Tunables can be set at startup via optional configuration files.
+ First, <filename>/usr/local/etc/ctdb/ctdb.tunables</filename> is
+ loaded, if this file exists. After this, all files with names
+ matching <filename>*.tunables</filename> in directory
+ <filename>/usr/local/etc/ctdb/tunables.d/</filename> are loaded
+ in the current locale's collation order, if the directory
+ exists.
+ </para>
+
+ <para>
+ The format of lines in tunables files is:
<literallayout>
<replaceable>TUNABLE</replaceable>=<replaceable>VALUE</replaceable>
@@ -722,6 +730,7 @@ MonitorInterval=20
<simplelist>
<member><filename>/usr/local/etc/ctdb/ctdb.tunables</filename></member>
+
<member><filename>/usr/local/etc/ctdb/tunables.d/*.tunables</filename></member>
</simplelist>
</refsect1>
diff --git a/ctdb/server/ctdb_tunables.c b/ctdb/server/ctdb_tunables.c
index 0dce656a93c..66c4d2d645b 100644
--- a/ctdb/server/ctdb_tunables.c
+++ b/ctdb/server/ctdb_tunables.c
@@ -1,4 +1,4 @@
-/*
+/*
ctdb tunables code
Copyright (C) Andrew Tridgell 2007
@@ -7,12 +7,12 @@
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
@@ -142,12 +142,10 @@ int32_t ctdb_control_list_tunables(struct ctdb_context
*ctdb, TDB_DATA *outdata)
bool ctdb_tunables_load(struct ctdb_context *ctdb)
{
- bool status;
+ bool status = false; /* fail by default */
+ bool dir_status = false;
TALLOC_CTX *tmp_ctx;
- char *file = NULL;
-
- /* Fail by default */
- status = false;
+ char *path = NULL;
tmp_ctx = talloc_new(ctdb);
if (tmp_ctx == NULL) {
@@ -155,15 +153,35 @@ bool ctdb_tunables_load(struct ctdb_context *ctdb)
goto done;
}
- file = path_etcdir_append(tmp_ctx, "ctdb.tunables");
- if (file == NULL) {
+ ctdb_tunable_set_defaults(&ctdb->tunable);
+
+ path = path_etcdir_append(tmp_ctx, "ctdb.tunables");
+ if (path == NULL) {
D_ERR("Failed to construct path for ctdb.tunables\n");
goto done;
}
- status = ctdb_tunable_load_file(tmp_ctx, &ctdb->tunable, file);
- /* No need to log error, already logged above */
+ status = ctdb_tunable_load_file(tmp_ctx, &ctdb->tunable, path);
+ /*
+ * Continue loading directory on failure to avoid forcing a
+ * typo-prone admin to play whack-a-mole. Final result is
+ * still failure.
+ */
+
+ /* Avoid talloc confusion in static analysers... */
+ talloc_free(path);
+
+ path = path_etcdir_append(tmp_ctx, "tunables.d");
+ if (path == NULL) {
+ D_ERR("Failed to construct path for tunables.d\n");
+ goto done;
+ }
+
+ dir_status = ctdb_tunable_load_directory(tmp_ctx, &ctdb->tunable, path);
+ if (!dir_status) {
+ status = false;
+ }
done:
talloc_free(tmp_ctx);
return status;
diff --git a/ctdb/tests/UNIT/cunit/tunable_test_001.sh
b/ctdb/tests/UNIT/cunit/tunable_test_001.sh
index c68cd69c64a..a639c8772cb 100755
--- a/ctdb/tests/UNIT/cunit/tunable_test_001.sh
+++ b/ctdb/tests/UNIT/cunit/tunable_test_001.sh
@@ -3,10 +3,14 @@
. "${TEST_SCRIPTS_DIR}/unit.sh"
tfile="${CTDB_TEST_TMP_DIR}/tunable.$$"
+tfile2="${CTDB_TEST_TMP_DIR}/tunable2.$$"
+tdir="${CTDB_TEST_TMP_DIR}/tunabled.$$"
-remove_files ()
+remove_files()
{
- rm -f "$tfile"
+ rm -f "$tfile" "$tfile2"
+ rm -f "${tdir}/"* 2>/dev/null || true
+ rmdir "$tdir" 2>/dev/null || true
}
test_cleanup remove_files
@@ -62,15 +66,61 @@ IPAllocAlgorithm=2
AllowMixedVersions=0
"
-ok_tunable_defaults ()
+ok_tunable_defaults()
{
ok "$defaults"
}
+tunable_log()
+{
+ _level="$1"
+ _msg="$2"
+
+ _all=":DEBUG:INFO:NOTICE:WARNING:ERR:"
+ # Keep the debug levels log at. This strips off the levels up
+ # to and including the current $CTDB_DEBUGLEVEL, but then puts
+ # back $CTDB_DEBUGLEVEL. Cheaper than a loop...
+ _want=":${CTDB_DEBUGLEVEL}:${_all#*":${CTDB_DEBUGLEVEL}:"}"
+
+ case "$_want" in
+ *":${_level}:"*)
+ log="${log}${_msg}
+" # Intentional newline
+ ;;
+ esac
+}
+
+# Update $_map with tunable settings from 1 file
+# values
+ok_tunable_1()
+{
+ _file="$1"
+
+ if [ ! -r "$_file" ]; then
+ tunable_log "INFO" "Optional tunables file ${_file} not found"
+ return
+ fi
+
+ tunable_log "NOTICE" "Loading tunables from ${_file}"
+
+ while IFS='= ' read -r _var _val; do
+ case "$_var" in
+ \#* | "") continue ;;
+ esac
+ _decval=$((_val))
+ _vl=$(echo "$_var" | tr '[:upper:]' '[:lower:]')
+ _map=$(echo "$_map" |
+ sed -e "s|^\\(${_vl}:.*=\\).*\$|\\1${_decval}|")
+ done <"$_file"
+}
+
# Set required output to a version of $defaults where values for
-# tunables specified in $tfile replace the default values
-ok_tunable ()
+# tunables specified in the given file(s) replace the default values
+ok_tunable()
{
+ _f1="${1:-"${tfile}"}"
+ _f2="${2:-""}"
+
# Construct a version of $defaults prepended with a lowercase
# version of the tunable variable, to allow case-insensitive
# matching. This would be easier with the GNU sed
@@ -78,23 +128,37 @@ ok_tunable ()
# condition in awk causes empty lines to be skipped, in case
# there are trailing empty lines in $defaults.
_map=$(echo "$defaults" |
- awk -F= '$0 { printf "%s:%s=%s\n", tolower($1), $1, $2 }')
-
- # Replace values for tunables set in $tfile
- while IFS='= ' read -r _var _val ; do
- case "$_var" in
- \#* | "") continue ;;
- esac
- _decval=$((_val))
- _vl=$(echo "$_var" | tr '[:upper:]' '[:lower:]')
- _map=$(echo "$_map" |
- sed -e "s|^\\(${_vl}:.*=\\).*\$|\\1${_decval}|")
- done <"$tfile"
+ awk -F= '$0 { printf "%s:%s=%s\n", tolower($1), $1, $2 }')
+
+ log=""
+
+ #
+ # Replace values for tunables that are set in each file
+ #
+
+ ok_tunable_1 "$_f1"
+
+ if [ -n "$_f2" ]; then
+ if [ -f "$_f2" ]; then
+ ok_tunable_1 "$_f2"
+ elif [ -d "$_f2" ]; then
+ for _t in "${_f2}/"*.tunables; do
+ if [ ! -e "$_t" ]; then
+ break
+ fi
+ ok_tunable_1 "$_t"
+ done
+ elif [ ! -e "$_f2" ]; then
+ tunable_log "INFO" "Optional tunables directory ${_f2}
not found"
+ fi
+ fi
# Set result, stripping off lowercase tunable prefix
- ok "$(echo "$_map" | awk -F: '{ print $2 }')"
+ ok "${log}$(echo "$_map" | awk -F: '{ print $2 }')"
}
+export CTDB_DEBUGLEVEL="INFO"
+
test_case "Unreadable file"
: >"$tfile"
chmod a-r "$tfile"
@@ -113,35 +177,40 @@ rm -f "$tfile"
test_case "Invalid file, contains 1 word"
echo "Hello" >"$tfile"
required_error EINVAL <<EOF
-ctdb_tunable_load_file: Invalid line containing "Hello"
+Loading tunables from ${tfile}
+${tfile}: Invalid tunables line containing "Hello"
EOF
unit_test tunable_test "$tfile"
test_case "Invalid file, contains multiple words"
echo "Hello world!" >"$tfile"
required_error EINVAL <<EOF
-ctdb_tunable_load_file: Invalid line containing "Hello world!"
+Loading tunables from ${tfile}
+${tfile}: Invalid tunables line containing "Hello world!"
EOF
unit_test tunable_test "$tfile"
test_case "Invalid file, missing value"
echo "EnableBans=" >"$tfile"
required_error EINVAL <<EOF
-ctdb_tunable_load_file: Invalid line containing "EnableBans"
+Loading tunables from ${tfile}
+${tfile}: Invalid tunables line containing "EnableBans"
EOF
unit_test tunable_test "$tfile"
test_case "Invalid file, invalid value (not a number)"
echo "EnableBans=value" >"$tfile"
required_error EINVAL <<EOF
-ctdb_tunable_load_file: Invalid value "value" for tunable "EnableBans"
+Loading tunables from ${tfile}
+${tfile}: Invalid value "value" for tunable "EnableBans"
EOF
unit_test tunable_test "$tfile"
test_case "Invalid file, missing key"
echo "=123" >"$tfile"
required_error EINVAL <<EOF
-ctdb_tunable_load_file: Syntax error
+Loading tunables from ${tfile}
+${tfile}: Syntax error
EOF
unit_test tunable_test "$tfile"
@@ -150,28 +219,32 @@ cat >"$tfile" <<EOF
=0
--
Samba Shared Repository