summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Lehnardt <jan@apache.org>2020-01-04 12:13:38 +0100
committerGitHub <noreply@github.com>2020-01-04 12:13:38 +0100
commit0cdd5f035015a1e691008e8affac58ee9463f9fb (patch)
tree1a0f04b91ff00898e1e65fff8084ff5400ad827b
parent8e1165f0c88ad8bc960e16e3061170ff00cd8719 (diff)
downloadcouchdb-0cdd5f035015a1e691008e8affac58ee9463f9fb.tar.gz
Refuse startup with no server admin set up (#2389)
feat: refuse startup with no server admin set up includes an admin party assert escape hatch for tests adds a log message every 5 minutes, if escape hatch is enabled. should play nice with systemd restart policies Co-authored-by: Joan Touzet <wohali@users.noreply.github.com>
-rw-r--r--Makefile9
-rw-r--r--Makefile.win6
-rwxr-xr-xbuild-aux/show-test-results.py112
-rw-r--r--src/couch/src/couch_sup.erl30
4 files changed, 87 insertions, 70 deletions
diff --git a/Makefile b/Makefile
index 1b649980f..9bcd389be 100644
--- a/Makefile
+++ b/Makefile
@@ -169,6 +169,7 @@ endif
eunit: export BUILDDIR = $(shell pwd)
eunit: export ERL_AFLAGS = -config $(shell pwd)/rel/files/eunit.config
eunit: export COUCHDB_QUERY_SERVER_JAVASCRIPT = $(shell pwd)/bin/couchjs $(shell pwd)/share/server/main.js
+eunit: export COUCHDB_TEST_ADMIN_PARTY_OVERRIDE=1
eunit: couch
@COUCHDB_VERSION=$(COUCHDB_VERSION) COUCHDB_GIT_SHA=$(COUCHDB_GIT_SHA) $(REBAR) setup_eunit 2> /dev/null
@for dir in $(subdirs); do \
@@ -223,7 +224,7 @@ python-black: .venv/bin/black
@python3 -c "import sys; exit(1 if sys.version_info >= (3,6) else 0)" || \
LC_ALL=C.UTF-8 LANG=C.UTF-8 .venv/bin/black --check \
--exclude="build/|buck-out/|dist/|_build/|\.git/|\.hg/|\.mypy_cache/|\.nox/|\.tox/|\.venv/|src/rebar/pr2relnotes.py|src/fauxton" \
- . dev/run "$(TEST_OPTS)" rel/overlay/bin/couchup test/javascript/run
+ . dev/run rel/overlay/bin/couchup test/javascript/run
python-black-update: .venv/bin/black
@python3 -c "import sys; exit(1 if sys.version_info < (3,6) else 0)" || \
@@ -235,6 +236,7 @@ python-black-update: .venv/bin/black
.PHONY: elixir
elixir: export MIX_ENV=integration
+elixir: export COUCHDB_TEST_ADMIN_PARTY_OVERRIDE=1
elixir: elixir-init elixir-check-formatted elixir-credo devclean
@dev/run "$(TEST_OPTS)" -a adm:pass -n 1 --no-eval 'mix test --trace --exclude without_quorum_test --exclude with_quorum_test $(EXUNIT_OPTS)'
@@ -269,6 +271,7 @@ elixir-credo: elixir-init
.PHONY: javascript
# target: javascript - Run JavaScript test suites or specific ones defined by suites option
+javascript: export COUCHDB_TEST_ADMIN_PARTY_OVERRIDE=1
javascript: devclean
@mkdir -p share/www/script/test
ifeq ($(IN_RELEASE), true)
@@ -284,6 +287,7 @@ endif
--ignore "$(ignore_js_suites)"'
.PHONY: test-cluster-with-quorum
+test-cluster-with-quorum: export COUCHDB_TEST_ADMIN_PARTY_OVERRIDE=1
test-cluster-with-quorum: devclean
@mkdir -p share/www/script/test
ifeq ($(IN_RELEASE), true)
@@ -300,6 +304,7 @@ endif
--path test/javascript/tests-cluster/with-quorum'
.PHONY: test-cluster-without-quorum
+test-cluster-without-quorum: export COUCHDB_TEST_ADMIN_PARTY_OVERRIDE=1
test-cluster-without-quorum: devclean
@mkdir -p share/www/script/test
ifeq ($(IN_RELEASE), true)
@@ -316,6 +321,7 @@ endif
--path test/javascript/tests-cluster/without-quorum'
.PHONY: soak-javascript
+soak-javascript: export COUCHDB_TEST_ADMIN_PARTY_OVERRIDE=1
soak-javascript:
@mkdir -p share/www/script/test
ifeq ($(IN_RELEASE), true)
@@ -370,6 +376,7 @@ build-test:
.PHONY: mango-test
# target: mango-test - Run Mango tests
+mango-test: export COUCHDB_TEST_ADMIN_PARTY_OVERRIDE=1
mango-test: devclean all
@cd src/mango && \
python3 -m venv .venv && \
diff --git a/Makefile.win b/Makefile.win
index 77cbcbf4b..c74a54621 100644
--- a/Makefile.win
+++ b/Makefile.win
@@ -140,6 +140,7 @@ check: all
eunit: export ERL_AFLAGS = $(shell echo "-config rel/files/eunit.config")
eunit: export BUILDDIR = $(shell echo %cd%)
eunit: export COUCHDB_QUERY_SERVER_JAVASCRIPT = $(shell echo %cd%)/bin/couchjs $(shell echo %cd%)/share/server/main.js
+eunit: export COUCHDB_TEST_ADMIN_PARTY_OVERRIDE=1
eunit: couch
@set COUCHDB_VERSION=$(COUCHDB_VERSION) && set COUCHDB_GIT_SHA=$(COUCHDB_GIT_SHA) && $(REBAR) setup_eunit 2> nul
@set COUCHDB_VERSION=$(COUCHDB_VERSION) && set COUCHDB_GIT_SHA=$(COUCHDB_GIT_SHA) && $(REBAR) -r eunit $(EUNIT_OPTS)
@@ -186,6 +187,7 @@ python-black-update: .venv/bin/black
. dev\run rel\overlay\bin\couchup test\javascript\run
.PHONY: elixir
+elixir: export COUCHDB_TEST_ADMIN_PARTY_OVERRIDE=1
elixir: elixir-init elixir-check-formatted elixir-credo devclean
@dev\run -a adm:pass --no-eval 'mix test --trace --exclude without_quorum_test --exclude with_quorum_test $(EXUNIT_OPTS)'
@@ -216,6 +218,7 @@ elixir-credo:
@mix credo
.PHONY: test-cluster-with-quorum
+test-cluster-with-quorum: export COUCHDB_TEST_ADMIN_PARTY_OVERRIDE=1
test-cluster-with-quorum: devclean
-@mkdir share\www\script\test
ifeq ($(IN_RELEASE), true)
@@ -232,6 +235,7 @@ endif
--path test\javascript\tests-cluster\with-quorum"
.PHONY: test-cluster-without-quorum
+test-cluster-without-quorum: export COUCHDB_TEST_ADMIN_PARTY_OVERRIDE=1
test-cluster-without-quorum: devclean
-@mkdir share\www\script\test
ifeq ($(IN_RELEASE), true)
@@ -250,6 +254,7 @@ endif
.PHONY: javascript
# target: javascript - Run JavaScript test suites or specific ones defined by suites option
+javascript: export COUCHDB_TEST_ADMIN_PARTY_OVERRIDE=1
javascript:
-@mkdir share\www\script\test
ifeq ($(IN_RELEASE), true)
@@ -266,6 +271,7 @@ endif
.PHONY: mango-test
+mango-test: export COUCHDB_TEST_ADMIN_PARTY_OVERRIDE=1
mango-test: devclean all
@cd src\mango && \
python.exe -m venv .venv && \
diff --git a/build-aux/show-test-results.py b/build-aux/show-test-results.py
index eecfc2e9d..05039653e 100755
--- a/build-aux/show-test-results.py
+++ b/build-aux/show-test-results.py
@@ -11,11 +11,10 @@ import xml.dom.minidom as md
TEST_COLLECTIONS = {
"EUnit": "src/**/.eunit/*.xml",
"EXUnit": "_build/integration/lib/couchdbtest/*.xml",
- "Mango": "src/mango/*.xml"
+ "Mango": "src/mango/*.xml",
}
-
def _attrs(elem):
ret = {}
for (k, v) in elem.attributes.items():
@@ -30,7 +29,7 @@ def _text(elem):
rc.append(node.data)
else:
rc.append(self._text(node))
- return ''.join(rc)
+ return "".join(rc)
class TestCase(object):
@@ -79,17 +78,14 @@ class TestCase(object):
def _name(self, attrs):
klass = attrs.get("classname", "")
if klass.startswith("Elixir."):
- klass = klass[len("Elixir."):]
+ klass = klass[len("Elixir.") :]
if klass:
return "%s - %s" % (klass, attrs["name"])
return attrs["name"]
class TestSuite(object):
- SUITE_NAME_PATTERNS = [
- re.compile("module '([^']+)'"),
- re.compile("Elixir\.(.+)")
- ]
+ SUITE_NAME_PATTERNS = [re.compile("module '([^']+)'"), re.compile("Elixir\.(.+)")]
def __init__(self, elem):
self.elem = elem
@@ -151,53 +147,42 @@ class TestCollection(object):
def parse_args():
parser = argparse.ArgumentParser(description="Show test result summaries")
parser.add_argument(
- "--ignore-failures",
- action="store_true",
- default=False,
- help="Don't display test failures"
- )
+ "--ignore-failures",
+ action="store_true",
+ default=False,
+ help="Don't display test failures",
+ )
parser.add_argument(
- "--ignore-errors",
- action="store_true",
- default=False,
- help="Don't display test errors"
- )
+ "--ignore-errors",
+ action="store_true",
+ default=False,
+ help="Don't display test errors",
+ )
parser.add_argument(
- "--ignore-skipped",
- action="store_true",
- default=False,
- help="Don't display skipped tests"
- )
+ "--ignore-skipped",
+ action="store_true",
+ default=False,
+ help="Don't display skipped tests",
+ )
parser.add_argument(
- "--all",
- type=int,
- default=0,
- help="Number of rows to show for all groups"
- )
+ "--all", type=int, default=0, help="Number of rows to show for all groups"
+ )
parser.add_argument(
- "--collection",
- action="append",
- default=[],
- help="Which collection to display. May be repeated."
- )
+ "--collection",
+ action="append",
+ default=[],
+ help="Which collection to display. May be repeated.",
+ )
parser.add_argument(
- "--suites",
- type=int,
- default=0,
- help="Number of suites to show"
- )
+ "--suites", type=int, default=0, help="Number of suites to show"
+ )
+ parser.add_argument("--tests", type=int, default=0, help="Number of tests to show")
parser.add_argument(
- "--tests",
- type=int,
- default=0,
- help="Number of tests to show"
- )
- parser.add_argument(
- "--sort",
- default="total",
- choices=["test", "fixture", "total"],
- help="Timing column to sort on"
- )
+ "--sort",
+ default="total",
+ choices=["test", "fixture", "total"],
+ help="Timing column to sort on",
+ )
return parser.parse_args()
@@ -304,7 +289,7 @@ def display_collections(collections, sort):
num_failures,
num_errors,
num_skipped,
- collection.name + " "
+ collection.name + " ",
)
rows.append(cols)
@@ -313,22 +298,16 @@ def display_collections(collections, sort):
scol = 1
elif sort == "test":
scol = 2
+
def skey(row):
return (-1.0 * row[scol], row[-1])
+
rows.sort(key=skey)
print "Collections"
print "==========="
print
- headers = [
- "Total",
- "Fixture",
- "Test",
- "Count",
- "Failed",
- "Errors",
- "Skipped"
- ]
+ headers = ["Total", "Fixture", "Test", "Count", "Failed", "Errors", "Skipped"]
display_table([headers] + rows)
print
@@ -345,7 +324,7 @@ def display_suites(collections, count, sort):
suite.num_failures,
suite.num_errors,
suite.num_skipped,
- collection.name + " - " + suite.name
+ collection.name + " - " + suite.name,
]
rows.append(cols)
@@ -354,8 +333,10 @@ def display_suites(collections, count, sort):
scol = 1
elif sort == "test":
scol = 2
+
def skey(row):
return (-1.0 * row[scol], row[-1])
+
rows.sort(key=skey)
rows = rows[:count]
@@ -363,15 +344,7 @@ def display_suites(collections, count, sort):
print "Suites"
print "======"
print
- headers = [
- "Total",
- "Fixture",
- "Test",
- "Count",
- "Failed",
- "Errors",
- "Skipped"
- ]
+ headers = ["Total", "Fixture", "Test", "Count", "Failed", "Errors", "Skipped"]
display_table([headers] + rows)
print
@@ -389,6 +362,7 @@ def display_tests(collections, count):
def skey(row):
return (-1.0 * row[0], row[-1])
+
rows.sort(key=skey)
rows = rows[:count]
diff --git a/src/couch/src/couch_sup.erl b/src/couch/src/couch_sup.erl
index 8dcaf1dc7..ac117ea43 100644
--- a/src/couch/src/couch_sup.erl
+++ b/src/couch/src/couch_sup.erl
@@ -28,6 +28,8 @@
start_link() ->
+ assert_admins(),
+ maybe_launch_admin_annoyance_reporter(),
write_pidfile(),
notify_starting(),
@@ -87,6 +89,34 @@ handle_config_change(_, _, _, _, _) ->
handle_config_terminate(_Server, _Reason, _State) ->
ok.
+assert_admins() ->
+ couch_log:info("Preflight check: Asserting Admin Account~n", []),
+ case {config:get("admins"), os:getenv("COUCHDB_TEST_ADMIN_PARTY_OVERRIDE")} of
+ {[], false} ->
+ couch_log:info("~n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%~n"
+ ++ " No Admin Account Found, aborting startup. ~n"
+ ++ " Please configure an admin account in your local.ini file. ~n"
+ ++ "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%~n", []),
+ % Wait a second so the log message can make it to the log
+ timer:sleep(500),
+ throw(admin_account_required);
+ _ -> ok
+ end.
+
+send_no_admin_account_error_message() ->
+ couch_log:error("No Admin Account configured."
+ ++ " Please configure an Admin Account in your local.ini file and restart CouchDB.~n", []),
+ FiveMinutes = 5 * 1000 * 60,
+ timer:sleep(FiveMinutes),
+ send_no_admin_account_error_message().
+
+maybe_launch_admin_annoyance_reporter() ->
+ case os:getenv("COUCHDB_TEST_ADMIN_PARTY_OVERRIDE") of
+ false -> ok;
+ _ -> spawn_link(fun send_no_admin_account_error_message/0)
+ end.
+
+
notify_starting() ->
couch_log:info("Apache CouchDB ~s is starting.~n", [
couch_server:get_version()