feat(admin-config-tool): drop ha/data/ entirely, match real client TLS
deploy-ha.sh no longer takes a <data-dir> argument or --build-config
flag. Every deploy now generates a fresh self-signed TLS cert/key
(openssl, RSA 2048, 10y validity) directly into the deploy dir's
certs/, and builds cluster.bin directly into controller/ctrl-1/conf/
via xceadmin -- no intermediate staging directory, nothing preserved
across runs. run-ha-soak.sh (/xce-test-ha) updated to match: dropped
its own XCE_HA_DATADIR-based precondition entirely. Updated 4 callers
(run-ha-soak.sh, test-heartbeat-tolerance.sh, test-commit-durability.sh,
both xce-deploy-ha/xce-test-ha SKILL.md docs).
Separately: xcecommon.wire.connect() was loading a client-side TLS
cert, diverging from the real reference client -- netio.c's
create_ssl_context() presents no certificate at all when acting as a
client (cert_file/key_file both NULL, bare TLS_client_method()).
Fixed connect() to match, and since nothing else consumed cert_dir
(verify_mode=CERT_NONE throughout, no CA check either), removed it
end-to-end: discovery.follow_redirects(), push.push_config()/
probe_config(), and the --cert-dir CLI flag.
Server-side cert loading (mock TLS test servers) is unaffected --
moved into a shared session-scoped tls_certs fixture (new
tests/conftest.py, openssl-generated) replacing 3 duplicated
REPO_HA_DATA_DIR/skipif blocks. Net result: those tests no longer skip
under a hermetic nix build sandbox (which never had ha/data/) --
verified 165/165 passed, 0 skipped, via both meson compile and a full
nix build --option sandbox false .#xcecore_debug rebuild (previously
128 passed / 37 skipped there).
ha/data/{xce.crt,xce.key} removed from git tracking. Requirements
2.3/2.4 and 8.3/8.4/8.5 marked superseded in requirements.md with
dated correction notes.
This commit is contained in:
parent
db2b5f17f0
commit
ee8473bd99
20 changed files with 244 additions and 297 deletions
|
|
@ -26,20 +26,10 @@ from xcecommon.errors import ConnectionTimeoutError, NoPrimaryError, ReplyDecode
|
|||
from xcecommon.schema import load_schema
|
||||
from xceadmin import push
|
||||
|
||||
REPO_HA_DATA_DIR = Path(__file__).resolve().parents[3] / "ha" / "data"
|
||||
CERT_FILE = REPO_HA_DATA_DIR / "xce.crt"
|
||||
KEY_FILE = REPO_HA_DATA_DIR / "xce.key"
|
||||
CERT_DIR = str(REPO_HA_DATA_DIR)
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
not (CERT_FILE.is_file() and KEY_FILE.is_file()),
|
||||
reason="ha/data/xce.crt or ha/data/xce.key not present",
|
||||
)
|
||||
|
||||
|
||||
def _server_context() -> ssl.SSLContext:
|
||||
def _server_context(cert_file: Path, key_file: Path) -> ssl.SSLContext:
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||
context.load_cert_chain(certfile=str(CERT_FILE), keyfile=str(KEY_FILE))
|
||||
context.load_cert_chain(certfile=str(cert_file), keyfile=str(key_file))
|
||||
return context
|
||||
|
||||
|
||||
|
|
@ -48,8 +38,10 @@ class _MockController:
|
|||
accepted TLS socket to ``handler``, then closes.
|
||||
"""
|
||||
|
||||
def __init__(self, handler):
|
||||
def __init__(self, handler, cert_file: Path, key_file: Path):
|
||||
self._handler = handler
|
||||
self._cert_file = cert_file
|
||||
self._key_file = key_file
|
||||
self._listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self._listener.bind(("127.0.0.1", 0))
|
||||
self._listener.listen(1)
|
||||
|
|
@ -63,7 +55,9 @@ class _MockController:
|
|||
except OSError:
|
||||
return
|
||||
try:
|
||||
tls_conn = _server_context().wrap_socket(raw_conn, server_side=True)
|
||||
tls_conn = _server_context(self._cert_file, self._key_file).wrap_socket(
|
||||
raw_conn, server_side=True
|
||||
)
|
||||
except (ssl.SSLError, OSError):
|
||||
raw_conn.close()
|
||||
return
|
||||
|
|
@ -80,11 +74,11 @@ class _MockController:
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_controller():
|
||||
def mock_controller(tls_certs):
|
||||
servers: list[_MockController] = []
|
||||
|
||||
def _make(handler) -> _MockController:
|
||||
srv = _MockController(handler)
|
||||
srv = _MockController(handler, tls_certs.cert_file, tls_certs.key_file)
|
||||
servers.append(srv)
|
||||
return srv
|
||||
|
||||
|
|
@ -127,7 +121,7 @@ def test_push_config_successful_commit(mock_controller, cluster_bin):
|
|||
|
||||
srv = mock_controller(_handler)
|
||||
|
||||
result = push.push_config(cluster_bin, f"127.0.0.1:{srv.port}", CERT_DIR)
|
||||
result = push.push_config(cluster_bin, f"127.0.0.1:{srv.port}")
|
||||
|
||||
assert result.version_tag == 7
|
||||
assert result.acked_count == 3
|
||||
|
|
@ -166,7 +160,7 @@ def test_push_config_follows_one_redirect_to_primary(mock_controller, cluster_bi
|
|||
_standby_handler.primary_port = primary_srv.port
|
||||
standby_srv = mock_controller(_standby_handler)
|
||||
|
||||
result = push.push_config(cluster_bin, f"127.0.0.1:{standby_srv.port}", CERT_DIR)
|
||||
result = push.push_config(cluster_bin, f"127.0.0.1:{standby_srv.port}")
|
||||
|
||||
assert result.version_tag == 9
|
||||
assert result.acked_count == 2
|
||||
|
|
@ -184,7 +178,7 @@ def test_push_config_non_zero_status_reports_error_not_exception(mock_controller
|
|||
|
||||
srv = mock_controller(_handler)
|
||||
|
||||
result = push.push_config(cluster_bin, f"127.0.0.1:{srv.port}", CERT_DIR)
|
||||
result = push.push_config(cluster_bin, f"127.0.0.1:{srv.port}")
|
||||
|
||||
assert result.acked_count == 0
|
||||
assert "status 1" in result.error
|
||||
|
|
@ -203,7 +197,7 @@ def test_push_config_wrong_reply_variant_raises_reply_decode_error(mock_controll
|
|||
srv = mock_controller(_handler)
|
||||
|
||||
with pytest.raises(ReplyDecodeError):
|
||||
push.push_config(cluster_bin, f"127.0.0.1:{srv.port}", CERT_DIR)
|
||||
push.push_config(cluster_bin, f"127.0.0.1:{srv.port}")
|
||||
|
||||
|
||||
def test_push_config_default_port_used_when_omitted():
|
||||
|
|
@ -239,7 +233,7 @@ def test_probe_config_reports_current_and_would_be_generation(mock_controller, c
|
|||
|
||||
srv = mock_controller(_handler)
|
||||
|
||||
result = push.probe_config(cluster_bin, f"127.0.0.1:{srv.port}", CERT_DIR)
|
||||
result = push.probe_config(cluster_bin, f"127.0.0.1:{srv.port}")
|
||||
|
||||
assert result.current_generation == 41
|
||||
assert result.would_be_generation == 42
|
||||
|
|
@ -263,7 +257,7 @@ def test_probe_config_zero_generation_still_accepted(mock_controller, cluster_bi
|
|||
|
||||
srv = mock_controller(_handler)
|
||||
|
||||
result = push.probe_config(cluster_bin, f"127.0.0.1:{srv.port}", CERT_DIR)
|
||||
result = push.probe_config(cluster_bin, f"127.0.0.1:{srv.port}")
|
||||
|
||||
assert result.current_generation == 0
|
||||
assert result.would_be_generation == 1
|
||||
|
|
@ -296,7 +290,7 @@ def test_probe_config_has_no_wire_level_rejection_signal_by_design(
|
|||
|
||||
srv = mock_controller(_handler)
|
||||
|
||||
result = push.probe_config(cluster_bin, f"127.0.0.1:{srv.port}", CERT_DIR)
|
||||
result = push.probe_config(cluster_bin, f"127.0.0.1:{srv.port}")
|
||||
|
||||
assert result.accepted is True
|
||||
assert result.reason == ""
|
||||
|
|
@ -337,7 +331,7 @@ def test_push_config_propagates_too_many_redirects_end_to_end(mock_controller, c
|
|||
servers["e"] = mock_controller(_make_redirect_handler(lambda: 1))
|
||||
|
||||
with pytest.raises(TooManyRedirectsError):
|
||||
push.push_config(cluster_bin, f"127.0.0.1:{servers['a'].port}", CERT_DIR)
|
||||
push.push_config(cluster_bin, f"127.0.0.1:{servers['a'].port}")
|
||||
|
||||
|
||||
def test_push_config_propagates_no_primary_error_on_connection_timeout(cluster_bin, monkeypatch):
|
||||
|
|
@ -349,10 +343,10 @@ def test_push_config_propagates_no_primary_error_on_connection_timeout(cluster_b
|
|||
eventually raise on a genuine timeout.
|
||||
"""
|
||||
|
||||
def _fake_connect(host, port, cert_dir, timeout_s=30.0):
|
||||
def _fake_connect(host, port, timeout_s=30.0):
|
||||
raise ConnectionTimeoutError(f"timeout connecting to {host}:{port}", host, port)
|
||||
|
||||
monkeypatch.setattr(wire, "connect", _fake_connect)
|
||||
|
||||
with pytest.raises(NoPrimaryError):
|
||||
push.push_config(cluster_bin, "127.0.0.1:9991", CERT_DIR)
|
||||
push.push_config(cluster_bin, "127.0.0.1:9991")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue