diff options
author | Jan Lehnardt <jan@apache.org> | 2020-01-04 12:13:38 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-04 12:13:38 +0100 |
commit | 0cdd5f035015a1e691008e8affac58ee9463f9fb (patch) | |
tree | 1a0f04b91ff00898e1e65fff8084ff5400ad827b | |
parent | 8e1165f0c88ad8bc960e16e3061170ff00cd8719 (diff) | |
download | couchdb-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-- | Makefile | 9 | ||||
-rw-r--r-- | Makefile.win | 6 | ||||
-rwxr-xr-x | build-aux/show-test-results.py | 112 | ||||
-rw-r--r-- | src/couch/src/couch_sup.erl | 30 |
4 files changed, 87 insertions, 70 deletions
@@ -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() |