|
|
081b2d |
From e3dea0043973faf42f7756d840bc55aa8f143eb1 Mon Sep 17 00:00:00 2001
|
|
|
081b2d |
From: William Brown <firstyear@redhat.com>
|
|
|
081b2d |
Date: Wed, 15 Nov 2017 13:44:02 +1000
|
|
|
081b2d |
Subject: [PATCH] Ticket 49298 - Correct error codes with config restore.
|
|
|
081b2d |
|
|
|
081b2d |
Bug Description: The piece of code uses 0 as an error - not 1,
|
|
|
081b2d |
and in some cases did not even check the codes or use the
|
|
|
081b2d |
correct logic.
|
|
|
081b2d |
|
|
|
081b2d |
Fix Description: Cleanup dse_check_file to better check the
|
|
|
081b2d |
content of files and communicate issues to the admin. Correct
|
|
|
081b2d |
slapd_bootstrap_config to correctly handle the cases of removal
|
|
|
081b2d |
and restore.
|
|
|
081b2d |
|
|
|
081b2d |
https://pagure.io/389-ds-base/issue/49298
|
|
|
081b2d |
|
|
|
081b2d |
Author: wibrown
|
|
|
081b2d |
|
|
|
081b2d |
Review by: mreynoolds & spichugi
|
|
|
081b2d |
|
|
|
081b2d |
Signed-off-by: Mark Reynolds <mreynolds@redhat.com>
|
|
|
081b2d |
(cherry picked from commit 75e55e26579955adf058e8adcba9a28779583b7b)
|
|
|
081b2d |
---
|
|
|
081b2d |
.../suites/config/removed_config_49298_test.py | 81 ++++++++++++++++++++++
|
|
|
081b2d |
ldap/servers/slapd/config.c | 15 ++--
|
|
|
081b2d |
ldap/servers/slapd/dse.c | 42 ++++++++---
|
|
|
081b2d |
3 files changed, 119 insertions(+), 19 deletions(-)
|
|
|
081b2d |
create mode 100644 dirsrvtests/tests/suites/config/removed_config_49298_test.py
|
|
|
081b2d |
|
|
|
081b2d |
diff --git a/dirsrvtests/tests/suites/config/removed_config_49298_test.py b/dirsrvtests/tests/suites/config/removed_config_49298_test.py
|
|
|
081b2d |
new file mode 100644
|
|
|
081b2d |
index 000000000..e65236924
|
|
|
081b2d |
--- /dev/null
|
|
|
081b2d |
+++ b/dirsrvtests/tests/suites/config/removed_config_49298_test.py
|
|
|
081b2d |
@@ -0,0 +1,81 @@
|
|
|
081b2d |
+# --- BEGIN COPYRIGHT BLOCK ---
|
|
|
081b2d |
+# Copyright (C) 2017 Red Hat, Inc.
|
|
|
081b2d |
+# All rights reserved.
|
|
|
081b2d |
+#
|
|
|
081b2d |
+# License: GPL (version 3 or any later version).
|
|
|
081b2d |
+# See LICENSE for details.
|
|
|
081b2d |
+# --- END COPYRIGHT BLOCK ---
|
|
|
081b2d |
+#
|
|
|
081b2d |
+import pytest
|
|
|
081b2d |
+import os
|
|
|
081b2d |
+import logging
|
|
|
081b2d |
+import subprocess
|
|
|
081b2d |
+
|
|
|
081b2d |
+from lib389.topologies import topology_st as topo
|
|
|
081b2d |
+
|
|
|
081b2d |
+DEBUGGING = os.getenv("DEBUGGING", default=False)
|
|
|
081b2d |
+if DEBUGGING:
|
|
|
081b2d |
+ logging.getLogger(__name__).setLevel(logging.DEBUG)
|
|
|
081b2d |
+else:
|
|
|
081b2d |
+ logging.getLogger(__name__).setLevel(logging.INFO)
|
|
|
081b2d |
+log = logging.getLogger(__name__)
|
|
|
081b2d |
+
|
|
|
081b2d |
+def test_restore_config(topo):
|
|
|
081b2d |
+ """
|
|
|
081b2d |
+ Check that if a dse.ldif and backup are removed, that the server still starts.
|
|
|
081b2d |
+
|
|
|
081b2d |
+ :id: e1c38fa7-30bc-46f2-a934-f8336f387581
|
|
|
081b2d |
+ :setup: Standalone instance
|
|
|
081b2d |
+ :steps:
|
|
|
081b2d |
+ 1. Stop the instance
|
|
|
081b2d |
+ 2. Delete 'dse.ldif'
|
|
|
081b2d |
+ 3. Start the instance
|
|
|
081b2d |
+ :expectedresults:
|
|
|
081b2d |
+ 1. Steps 1 and 2 succeed.
|
|
|
081b2d |
+ 2. Server will succeed to start with restored cfg.
|
|
|
081b2d |
+ """
|
|
|
081b2d |
+ topo.standalone.stop()
|
|
|
081b2d |
+
|
|
|
081b2d |
+ dse_path = topo.standalone.get_config_dir()
|
|
|
081b2d |
+
|
|
|
081b2d |
+ log.info(dse_path)
|
|
|
081b2d |
+
|
|
|
081b2d |
+ for i in ('dse.ldif', 'dse.ldif.startOK'):
|
|
|
081b2d |
+ p = os.path.join(dse_path, i)
|
|
|
081b2d |
+ os.remove(p)
|
|
|
081b2d |
+
|
|
|
081b2d |
+ # This will pass.
|
|
|
081b2d |
+ topo.standalone.start()
|
|
|
081b2d |
+
|
|
|
081b2d |
+def test_removed_config(topo):
|
|
|
081b2d |
+ """
|
|
|
081b2d |
+ Check that if a dse.ldif and backup are removed, that the server
|
|
|
081b2d |
+ exits better than "segfault".
|
|
|
081b2d |
+
|
|
|
081b2d |
+ :id: b45272d1-c197-473e-872f-07257fcb2ec0
|
|
|
081b2d |
+ :setup: Standalone instance
|
|
|
081b2d |
+ :steps:
|
|
|
081b2d |
+ 1. Stop the instance
|
|
|
081b2d |
+ 2. Delete 'dse.ldif', 'dse.ldif.bak', 'dse.ldif.startOK'
|
|
|
081b2d |
+ 3. Start the instance
|
|
|
081b2d |
+ :expectedresults:
|
|
|
081b2d |
+ 1. Steps 1 and 2 succeed.
|
|
|
081b2d |
+ 2. Server will fail to start, but will not crash.
|
|
|
081b2d |
+ """
|
|
|
081b2d |
+ topo.standalone.stop()
|
|
|
081b2d |
+
|
|
|
081b2d |
+ dse_path = topo.standalone.get_config_dir()
|
|
|
081b2d |
+
|
|
|
081b2d |
+ log.info(dse_path)
|
|
|
081b2d |
+
|
|
|
081b2d |
+ for i in ('dse.ldif', 'dse.ldif.bak', 'dse.ldif.startOK'):
|
|
|
081b2d |
+ p = os.path.join(dse_path, i)
|
|
|
081b2d |
+ os.remove(p)
|
|
|
081b2d |
+
|
|
|
081b2d |
+ # We actually can't check the log output, because it can't read dse.ldif,
|
|
|
081b2d |
+ # don't know where to write it yet! All we want is the server fail to
|
|
|
081b2d |
+ # start here, rather than infinite run + segfault.
|
|
|
081b2d |
+ with pytest.raises(subprocess.CalledProcessError):
|
|
|
081b2d |
+ topo.standalone.start()
|
|
|
081b2d |
+
|
|
|
081b2d |
+
|
|
|
081b2d |
diff --git a/ldap/servers/slapd/config.c b/ldap/servers/slapd/config.c
|
|
|
081b2d |
index afe07df84..c8d57e747 100644
|
|
|
081b2d |
--- a/ldap/servers/slapd/config.c
|
|
|
081b2d |
+++ b/ldap/servers/slapd/config.c
|
|
|
081b2d |
@@ -121,14 +121,13 @@ slapd_bootstrap_config(const char *configdir)
|
|
|
081b2d |
"Passed null config directory\n");
|
|
|
081b2d |
return rc; /* Fail */
|
|
|
081b2d |
}
|
|
|
081b2d |
- PR_snprintf(configfile, sizeof(configfile), "%s/%s", configdir,
|
|
|
081b2d |
- CONFIG_FILENAME);
|
|
|
081b2d |
- PR_snprintf(tmpfile, sizeof(tmpfile), "%s/%s.tmp", configdir,
|
|
|
081b2d |
- CONFIG_FILENAME);
|
|
|
081b2d |
- if ((rc = dse_check_file(configfile, tmpfile)) == 0) {
|
|
|
081b2d |
- PR_snprintf(tmpfile, sizeof(tmpfile), "%s/%s.bak", configdir,
|
|
|
081b2d |
- CONFIG_FILENAME);
|
|
|
081b2d |
- rc = dse_check_file(configfile, tmpfile);
|
|
|
081b2d |
+ PR_snprintf(configfile, sizeof(configfile), "%s/%s", configdir, CONFIG_FILENAME);
|
|
|
081b2d |
+ PR_snprintf(tmpfile, sizeof(tmpfile), "%s/%s.bak", configdir, CONFIG_FILENAME);
|
|
|
081b2d |
+ rc = dse_check_file(configfile, tmpfile);
|
|
|
081b2d |
+ if (rc == 0) {
|
|
|
081b2d |
+ /* EVERYTHING IS GOING WRONG, ARRGHHHHHH */
|
|
|
081b2d |
+ slapi_log_err(SLAPI_LOG_ERR, "slapd_bootstrap_config", "No valid configurations can be accessed! You must restore %s from backup!\n", configfile);
|
|
|
081b2d |
+ return 0;
|
|
|
081b2d |
}
|
|
|
081b2d |
|
|
|
081b2d |
if ((rc = PR_GetFileInfo64(configfile, &prfinfo)) != PR_SUCCESS) {
|
|
|
081b2d |
diff --git a/ldap/servers/slapd/dse.c b/ldap/servers/slapd/dse.c
|
|
|
081b2d |
index 420248c24..653009f53 100644
|
|
|
081b2d |
--- a/ldap/servers/slapd/dse.c
|
|
|
081b2d |
+++ b/ldap/servers/slapd/dse.c
|
|
|
081b2d |
@@ -609,29 +609,49 @@ dse_check_file(char *filename, char *backupname)
|
|
|
081b2d |
|
|
|
081b2d |
if (PR_GetFileInfo64(filename, &prfinfo) == PR_SUCCESS) {
|
|
|
081b2d |
if (prfinfo.size > 0) {
|
|
|
081b2d |
- return (1);
|
|
|
081b2d |
+ /* File exists and has content. */
|
|
|
081b2d |
+ return 1;
|
|
|
081b2d |
} else {
|
|
|
081b2d |
+ slapi_log_err(SLAPI_LOG_INFO, "dse_check_file",
|
|
|
081b2d |
+ "The config %s has zero length. Attempting restore ... \n", filename, rc);
|
|
|
081b2d |
rc = PR_Delete(filename);
|
|
|
081b2d |
}
|
|
|
081b2d |
+ } else {
|
|
|
081b2d |
+ slapi_log_err(SLAPI_LOG_INFO, "dse_check_file",
|
|
|
081b2d |
+ "The config %s can not be accessed. Attempting restore ... (reason: %d)\n", filename, rc);
|
|
|
081b2d |
}
|
|
|
081b2d |
|
|
|
081b2d |
if (backupname) {
|
|
|
081b2d |
+
|
|
|
081b2d |
+ if (PR_GetFileInfo64(backupname, &prfinfo) != PR_SUCCESS) {
|
|
|
081b2d |
+ slapi_log_err(SLAPI_LOG_INFO, "dse_check_file",
|
|
|
081b2d |
+ "The backup %s can not be accessed. Check it exists and permissions.\n", backupname);
|
|
|
081b2d |
+ return 0;
|
|
|
081b2d |
+ }
|
|
|
081b2d |
+
|
|
|
081b2d |
+ if (prfinfo.size <= 0) {
|
|
|
081b2d |
+ slapi_log_err(SLAPI_LOG_ERR, "dse_check_file",
|
|
|
081b2d |
+ "The backup file %s has zero length, refusing to restore it.\n", backupname);
|
|
|
081b2d |
+ return 0;
|
|
|
081b2d |
+ }
|
|
|
081b2d |
+
|
|
|
081b2d |
rc = PR_Rename(backupname, filename);
|
|
|
081b2d |
- } else {
|
|
|
081b2d |
- return (0);
|
|
|
081b2d |
- }
|
|
|
081b2d |
+ if (rc != PR_SUCCESS) {
|
|
|
081b2d |
+ slapi_log_err(SLAPI_LOG_INFO, "dse_check_file",
|
|
|
081b2d |
+ "The configuration file %s was NOT able to be restored from %s, error %d\n", filename, backupname, rc);
|
|
|
081b2d |
+ return 0;
|
|
|
081b2d |
+ }
|
|
|
081b2d |
|
|
|
081b2d |
- if (PR_GetFileInfo64(filename, &prfinfo) == PR_SUCCESS && prfinfo.size > 0) {
|
|
|
081b2d |
slapi_log_err(SLAPI_LOG_INFO, "dse_check_file",
|
|
|
081b2d |
- "The configuration file %s was restored from backup %s\n", filename, backupname);
|
|
|
081b2d |
- return (1);
|
|
|
081b2d |
+ "The configuration file %s was restored from backup %s\n", filename, backupname);
|
|
|
081b2d |
+ return 1;
|
|
|
081b2d |
+
|
|
|
081b2d |
} else {
|
|
|
081b2d |
- slapi_log_err(SLAPI_LOG_ERR, "dse_check_file",
|
|
|
081b2d |
- "The configuration file %s was not restored from backup %s, error %d\n",
|
|
|
081b2d |
- filename, backupname, rc);
|
|
|
081b2d |
- return (0);
|
|
|
081b2d |
+ slapi_log_err(SLAPI_LOG_INFO, "dse_check_file", "No backup filename provided.\n");
|
|
|
081b2d |
+ return 0;
|
|
|
081b2d |
}
|
|
|
081b2d |
}
|
|
|
081b2d |
+
|
|
|
081b2d |
static int
|
|
|
081b2d |
dse_read_one_file(struct dse *pdse, const char *filename, Slapi_PBlock *pb, int primary_file)
|
|
|
081b2d |
{
|
|
|
081b2d |
--
|
|
|
081b2d |
2.13.6
|
|
|
081b2d |
|