From 6c82cc68c5ed74e0fd20e40f0333e736cb81a05e Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 25 Feb 2025 10:28:07 -0600 Subject: [PATCH 01/11] make cert paths configurable --- .../orchestration/drivers_orchestration.py | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/.evergreen/orchestration/drivers_orchestration.py b/.evergreen/orchestration/drivers_orchestration.py index 46dfe78cc..7e99a6dab 100644 --- a/.evergreen/orchestration/drivers_orchestration.py +++ b/.evergreen/orchestration/drivers_orchestration.py @@ -64,10 +64,10 @@ def get_options(): ) other_group = parser.add_argument_group("Other options") - parser.add_argument( + other_group.add_argument( "--load-balancer", action="store_true", help="Whether to use a load balancer" ) - parser.add_argument( + other_group.add_argument( "--skip-crypt-shared", action="store_true", help="Whether to skip installing crypt_shared lib", @@ -100,7 +100,19 @@ def get_options(): ) other_group.add_argument( "--existing-binaries-dir", - help="A directory containing existing mongodb binaries to use instead of downloading new ones.", + help="A directory containing existing mongodb binaries to use instead of downloading new ones", + ) + other_group.add_argument( + "--tls-cert-key-file", + help="A .pem to be used as the tlsCertificateKeyFile option in mongo-orchestration", + ) + other_group.add_argument( + "--tls-pem-key-file", + help="A .pem file that contains the TLS certificate and key for the server", + ) + other_group.add_argument( + "--tls-ca-file", + help="A .pem file that contains the root certificate chain for the server", ) # Get the options, and then allow environment variable overrides. @@ -276,7 +288,16 @@ def run(opts): orch_path = mo_home / f"configs/{topology}s/{orchestration_file}" LOGGER.info(f"Using orchestration file: {orch_path}") text = orch_path.read_text() - text = text.replace("ABSOLUTE_PATH_REPLACEMENT_TOKEN", DRIVERS_TOOLS.as_posix()) + + # Handle overriding the tls configuration in the file. + if opts.tls_pem_key_file or opts.tls_ca_file: + if not (opts.tls_pem_key_file and opts.tls_ca_file): + raise ValueError("You must supply both tls-pem-key-file and tls-ca-file") + base = "ABSOLUTE_PATH_REPLACEMENT_TOKEN/.evergreen/x509gen" + text = text.replace(f"{base}/server.pem", opts.tls_pem_key_file) + text = text.replace(f"{base}/ca.pem", opts.tls_ca_file) + else: + text = text.replace("ABSOLUTE_PATH_REPLACEMENT_TOKEN", DRIVERS_TOOLS.as_posix()) data = json.loads(text) if opts.require_api_version: @@ -385,6 +406,11 @@ def start(opts): ) command = "mongo-orchestration -s wsgiref" + # Override the client cert file if applicable. + env = os.environ.copy() + if opts.tls_cert_key_file: + env["MONGO_ORCHESTRATION_CLIENT_CERT"] = opts.tls_cert_key_file + mo_start = datetime.now() # Start the process. @@ -399,7 +425,11 @@ def start(opts): output_fid = output_file.open("w") try: subprocess.run( - shlex.split(args), check=True, stderr=subprocess.STDOUT, stdout=output_fid + shlex.split(args), + check=True, + stderr=subprocess.STDOUT, + stdout=output_fid, + env=env, ) except subprocess.CalledProcessError: LOGGER.error("Orchestration failed!") From b4f812e226fd772bbb9bfde9970f78e88393f598 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 25 Feb 2025 10:35:32 -0600 Subject: [PATCH 02/11] update docs --- .evergreen/run-orchestration.sh | 15 +++++++++------ README.md | 10 +++++----- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.evergreen/run-orchestration.sh b/.evergreen/run-orchestration.sh index 793822a81..de925ddec 100755 --- a/.evergreen/run-orchestration.sh +++ b/.evergreen/run-orchestration.sh @@ -6,17 +6,20 @@ set -eu # AUTH Set to "auth" to enable authentication. Defaults to "noauth" # SSL Set to "yes" to enable SSL. Defaults to "nossl" # TOPOLOGY Set to "server", "replica_set", or "sharded_cluster". Defaults to "server" (i.e. standalone). -# LOAD_BALANCER Set to a non-empty string to enable load balancer. Only supported for sharded clusters. +# MONGODB_VERSION Set the MongoDB version to use. Defaults to "latest". +# MONGODB_DOWNLOAD_URL Set the MongoDB download URL to use for download-mongodb.sh. +# ORCHESTRATION_FILE Set the /.json configuration. # STORAGE_ENGINE Set to a non-empty string to use the /.json configuration (e.g. STORAGE_ENGINE=inmemory). # REQUIRE_API_VERSION Set to a non-empty string to set the requireApiVersion parameter. Currently only supported for standalone servers. # DISABLE_TEST_COMMANDS Set to a non-empty string to use the /disableTestCommands.json configuration (e.g. DISABLE_TEST_COMMANDS=1). -# MONGODB_VERSION Set to a MongoDB version to use for download-mongodb.sh. Defaults to "latest". -# MONGODB_DOWNLOAD_URL Set to a MongoDB download URL to use for download-mongodb.sh. -# ORCHESTRATION_FILE Set to a non-empty string to use the /.json configuration. # SKIP_CRYPT_SHARED Set to a non-empty string to skip downloading crypt_shared -# MONGODB_BINARIES Set to a non-empty string to set the path to the MONGODB_BINARIES for mongo orchestration. -# PYTHON Set to a non-empty string to set the Python binary to use. +# MONGODB_BINARIES Set the path to the MONGODB_BINARIES for mongo orchestration. +# LOAD_BALANCER Set to a non-empty string to enable load balancer. Only supported for sharded clusters. +# PYTHON Set the Python binary to use. # INSTALL_LEGACY_SHELL Set to a non-empty string to install the legacy mongo shell. +# TLS_CERT_KEY_FILE Set a .pem file to be used as the tlsCertificateKeyFile option in mongo-orchestration +# TLS_PEM_KEY_FILE Set a .pem file that contains the TLS certificate and key for the server +# TLS_CA_FILE Set a .pem file that contains the root certificate chain for the server # See https://stackoverflow.com/questions/35006457/choosing-between-0-and-bash-source/35006505#35006505 # Why we need this syntax when sh is not aliased to bash (this script must be able to be called from sh) diff --git a/README.md b/README.md index 91efeffcd..3df2e2b67 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ There are two options for running a MongoDB server configuration. One is to use [docker](./.evergreen/docker/README.md). The other is to run `./evergreen/run-orchestration.sh` locally. For convenience, you can run `make run-server` and `make stop-server` to start and stop the server(s). + For example: ```bash @@ -94,13 +95,12 @@ TOPOLOGY=replica_set MONGODB_VERSION=7.0 make run-server See (run-orchestration.sh)[./evergreen/run-orchestration.sh] for the available environment variables. -In order to use custom certificates in your server, copy the client certificate file to -`$MONGO_ORCHESTRATION_HOME/lib/client.pem` (where `MONGO_ORCHESTRATION_HOME` -defaults to `$DRIVERS_TOOLS/.evergreen/orchestration`), e.g. +In order to use custom certificates in your server, set the following environment variables: ```bash -# Replace Mongo Orchestration's client certificate. -cp ${PROJECT_DIRECTORY}/test/certificates/client.pem ${MONGO_ORCHESTRATION_HOME}/lib/client.pem +export TLS_CERT_KEY_FILE=/client.pem +export TLS_PEM_KEY_FILE=/server.pem +export TLS_CA_FILE=/ca.pem ``` ## Linters and Formatters From 35b6499b301754a6116c5ba5990184bf5bfb309e Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 25 Feb 2025 11:56:55 -0600 Subject: [PATCH 03/11] fix windows paths --- .evergreen/orchestration/drivers_orchestration.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.evergreen/orchestration/drivers_orchestration.py b/.evergreen/orchestration/drivers_orchestration.py index 7e99a6dab..71542ce8d 100644 --- a/.evergreen/orchestration/drivers_orchestration.py +++ b/.evergreen/orchestration/drivers_orchestration.py @@ -294,8 +294,10 @@ def run(opts): if not (opts.tls_pem_key_file and opts.tls_ca_file): raise ValueError("You must supply both tls-pem-key-file and tls-ca-file") base = "ABSOLUTE_PATH_REPLACEMENT_TOKEN/.evergreen/x509gen" - text = text.replace(f"{base}/server.pem", opts.tls_pem_key_file) - text = text.replace(f"{base}/ca.pem", opts.tls_ca_file) + text = text.replace( + f"{base}/server.pem", Path(opts.tls_pem_key_file).as_posix() + ) + text = text.replace(f"{base}/ca.pem", Path(opts.tls_ca_file).as_posix()) else: text = text.replace("ABSOLUTE_PATH_REPLACEMENT_TOKEN", DRIVERS_TOOLS.as_posix()) data = json.loads(text) @@ -409,7 +411,7 @@ def start(opts): # Override the client cert file if applicable. env = os.environ.copy() if opts.tls_cert_key_file: - env["MONGO_ORCHESTRATION_CLIENT_CERT"] = opts.tls_cert_key_file + env["MONGO_ORCHESTRATION_CLIENT_CERT"] = Path(opts.tls_cert_key_file).as_posix() mo_start = datetime.now() From da044e241854ddadd11dd364bfdc2fddf4721f2e Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 25 Feb 2025 13:02:01 -0600 Subject: [PATCH 04/11] windows fix --- .evergreen/orchestration/drivers_orchestration.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.evergreen/orchestration/drivers_orchestration.py b/.evergreen/orchestration/drivers_orchestration.py index 71542ce8d..0ada60b25 100644 --- a/.evergreen/orchestration/drivers_orchestration.py +++ b/.evergreen/orchestration/drivers_orchestration.py @@ -295,9 +295,11 @@ def run(opts): raise ValueError("You must supply both tls-pem-key-file and tls-ca-file") base = "ABSOLUTE_PATH_REPLACEMENT_TOKEN/.evergreen/x509gen" text = text.replace( - f"{base}/server.pem", Path(opts.tls_pem_key_file).as_posix() + f"{base}/server.pem", str(opts.tls_pem_key_file).replace(os.sep, "/") + ) + text = text.replace( + f"{base}/ca.pem", str(opts.tls_ca_file).replace(os.sep, "/") ) - text = text.replace(f"{base}/ca.pem", Path(opts.tls_ca_file).as_posix()) else: text = text.replace("ABSOLUTE_PATH_REPLACEMENT_TOKEN", DRIVERS_TOOLS.as_posix()) data = json.loads(text) From 4f142b7b2455707c3c9a8c817c2e618ef8508547 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 25 Feb 2025 13:47:02 -0600 Subject: [PATCH 05/11] windows fix --- .evergreen/orchestration/drivers_orchestration.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.evergreen/orchestration/drivers_orchestration.py b/.evergreen/orchestration/drivers_orchestration.py index 0ada60b25..71542ce8d 100644 --- a/.evergreen/orchestration/drivers_orchestration.py +++ b/.evergreen/orchestration/drivers_orchestration.py @@ -295,11 +295,9 @@ def run(opts): raise ValueError("You must supply both tls-pem-key-file and tls-ca-file") base = "ABSOLUTE_PATH_REPLACEMENT_TOKEN/.evergreen/x509gen" text = text.replace( - f"{base}/server.pem", str(opts.tls_pem_key_file).replace(os.sep, "/") - ) - text = text.replace( - f"{base}/ca.pem", str(opts.tls_ca_file).replace(os.sep, "/") + f"{base}/server.pem", Path(opts.tls_pem_key_file).as_posix() ) + text = text.replace(f"{base}/ca.pem", Path(opts.tls_ca_file).as_posix()) else: text = text.replace("ABSOLUTE_PATH_REPLACEMENT_TOKEN", DRIVERS_TOOLS.as_posix()) data = json.loads(text) From fccbb36f88f1b18d2604505aacd2728896515e98 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 25 Feb 2025 16:08:30 -0600 Subject: [PATCH 06/11] normalize paths --- .../orchestration/drivers_orchestration.py | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/.evergreen/orchestration/drivers_orchestration.py b/.evergreen/orchestration/drivers_orchestration.py index 71542ce8d..cead36269 100644 --- a/.evergreen/orchestration/drivers_orchestration.py +++ b/.evergreen/orchestration/drivers_orchestration.py @@ -8,6 +8,7 @@ import json import logging import os +import re import shlex import shutil import socket @@ -184,13 +185,21 @@ def traverse(root): router["logpath"] = f"/tmp/mongodb-{item['port']}.log" +def normalize_path(path: Path | str) -> str: + path = Path(path).absolute + if os.name != "nt": + return path + path = path.as_posix() + return re.sub("/cygdrive/(.*?)(/)", r"\1://", path, count=1) + + def run(opts): LOGGER.info("Running orchestration...") # Clean up previous files. mdb_binaries = Path(opts.mongodb_binaries) - # NOTE: in general, we need to use posix strings to avoid path escapes on cygwin. - mdb_binaries_str = mdb_binaries.as_posix() + # NOTE: in general, we need to normalize paths to account for cygwin/Windows. + mdb_binaries_str = normalize_path(mdb_binaries) shutil.rmtree(mdb_binaries, ignore_errors=True) expansion_yaml = Path("mo-expansion.yml") expansion_yaml.unlink(missing_ok=True) @@ -205,7 +214,7 @@ def run(opts): dl_start = datetime.now() version = opts.version cache_dir = DRIVERS_TOOLS / ".local/cache" - cache_dir_str = cache_dir.as_posix() + cache_dir_str = normalize_path(cache_dir) default_args = f"--out {mdb_binaries_str} --cache-dir {cache_dir_str} --retries 5" if opts.quiet: default_args += " -q" @@ -237,7 +246,7 @@ def run(opts): # We download crypt_shared to DRIVERS_TOOLS so that it is on a different # path location than the other binaries, which is required for # https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.md#via-bypassautoencryption - args = default_args.replace(mdb_binaries_str, DRIVERS_TOOLS.as_posix()) + args = default_args.replace(mdb_binaries_str, normalize_path(DRIVERS_TOOLS)) args += ( f" --version {version} --strip-path-components 1 --component crypt_shared" ) @@ -250,7 +259,7 @@ def run(opts): if fname in expected: crypt_shared_path = DRIVERS_TOOLS / fname assert crypt_shared_path is not None - crypt_text = f'CRYPT_SHARED_LIB_PATH: "{crypt_shared_path.as_posix()}"' + crypt_text = f'CRYPT_SHARED_LIB_PATH: "{normalize_path(crypt_shared_path)}"' expansion_yaml.write_text(crypt_text) expansion_sh.write_text(crypt_text.replace(": ", "=")) @@ -294,12 +303,12 @@ def run(opts): if not (opts.tls_pem_key_file and opts.tls_ca_file): raise ValueError("You must supply both tls-pem-key-file and tls-ca-file") base = "ABSOLUTE_PATH_REPLACEMENT_TOKEN/.evergreen/x509gen" + text = text.replace(f"{base}/server.pem", normalize_path(opts.tls_pem_key_file)) + text = text.replace(f"{base}/ca.pem", normalize_path(opts.tls_ca_file)) + else: text = text.replace( - f"{base}/server.pem", Path(opts.tls_pem_key_file).as_posix() + "ABSOLUTE_PATH_REPLACEMENT_TOKEN", normalize_path(DRIVERS_TOOLS) ) - text = text.replace(f"{base}/ca.pem", Path(opts.tls_ca_file).as_posix()) - else: - text = text.replace("ABSOLUTE_PATH_REPLACEMENT_TOKEN", DRIVERS_TOOLS.as_posix()) data = json.loads(text) if opts.require_api_version: @@ -387,14 +396,15 @@ def start(opts): os.makedirs(mo_home / "lib", exist_ok=True) mo_config = mo_home / "orchestration.config" mdb_binaries = Path(opts.mongodb_binaries) - config = dict(releases=dict(default=mdb_binaries.as_posix())) + config = dict(releases=dict(default=normalize_path(mdb_binaries))) mo_config.write_text(json.dumps(config, indent=2)) - mo_config_str = mo_config.as_posix() - command = f"{sys.executable} -m mongo_orchestration.server" + mo_config_str = normalize_path(mo_config) + sys_executable = normalize_path(sys.executable) + command = f"{sys_executable} -m mongo_orchestration.server" # Handle Windows-specific concerns. if os.name == "nt": - # Copy client certificates. + # Copy default client certificate. src = DRIVERS_TOOLS / ".evergreen/x509gen/client.pem" dst = mo_home / "lib/client.pem" try: @@ -404,14 +414,14 @@ def start(opts): # We need to use the CLI executable, and add it to our path. os.environ["PATH"] = ( - f"{Path(sys.executable).parent}{os.pathsep}{os.environ['PATH']}" + f"{Path(sys_executable).parent}{os.pathsep}{os.environ['PATH']}" ) command = "mongo-orchestration -s wsgiref" # Override the client cert file if applicable. env = os.environ.copy() if opts.tls_cert_key_file: - env["MONGO_ORCHESTRATION_CLIENT_CERT"] = Path(opts.tls_cert_key_file).as_posix() + env["MONGO_ORCHESTRATION_CLIENT_CERT"] = normalize_path(opts.tls_cert_key_file) mo_start = datetime.now() @@ -462,7 +472,7 @@ def start(opts): def stop(): LOGGER.info("Stopping mongo-orchestration...") - py_exe = Path(sys.executable).as_posix() + py_exe = normalize_path(sys.executable) args = f"{py_exe} -m mongo_orchestration.server stop" proc = subprocess.run( shlex.split(args), check=True, stderr=subprocess.STDOUT, stdout=subprocess.PIPE From 19e7082e536862f3056675e451693cb8cab171b1 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 25 Feb 2025 16:12:30 -0600 Subject: [PATCH 07/11] fix path handling --- .evergreen/orchestration/drivers_orchestration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.evergreen/orchestration/drivers_orchestration.py b/.evergreen/orchestration/drivers_orchestration.py index cead36269..91d89ce32 100644 --- a/.evergreen/orchestration/drivers_orchestration.py +++ b/.evergreen/orchestration/drivers_orchestration.py @@ -188,7 +188,7 @@ def traverse(root): def normalize_path(path: Path | str) -> str: path = Path(path).absolute if os.name != "nt": - return path + return str(path) path = path.as_posix() return re.sub("/cygdrive/(.*?)(/)", r"\1://", path, count=1) From 44c8bdf27ea999b0a8777aea5a24e13870a6c833 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 25 Feb 2025 16:16:22 -0600 Subject: [PATCH 08/11] fix usage --- .evergreen/orchestration/drivers_orchestration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.evergreen/orchestration/drivers_orchestration.py b/.evergreen/orchestration/drivers_orchestration.py index 91d89ce32..bfa36855d 100644 --- a/.evergreen/orchestration/drivers_orchestration.py +++ b/.evergreen/orchestration/drivers_orchestration.py @@ -186,7 +186,7 @@ def traverse(root): def normalize_path(path: Path | str) -> str: - path = Path(path).absolute + path = Path(path).absolute() if os.name != "nt": return str(path) path = path.as_posix() From 1a524b4d8933222d4c28857e8970bc9041167e2d Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 25 Feb 2025 16:48:24 -0600 Subject: [PATCH 09/11] remove absolute handling --- .evergreen/orchestration/drivers_orchestration.py | 1 - 1 file changed, 1 deletion(-) diff --git a/.evergreen/orchestration/drivers_orchestration.py b/.evergreen/orchestration/drivers_orchestration.py index bfa36855d..04c271990 100644 --- a/.evergreen/orchestration/drivers_orchestration.py +++ b/.evergreen/orchestration/drivers_orchestration.py @@ -186,7 +186,6 @@ def traverse(root): def normalize_path(path: Path | str) -> str: - path = Path(path).absolute() if os.name != "nt": return str(path) path = path.as_posix() From 8b61ca962e0487cd4e0f23e1a0968e13f554ea1a Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 25 Feb 2025 16:54:16 -0600 Subject: [PATCH 10/11] fix windows paths --- .evergreen/orchestration/drivers_orchestration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.evergreen/orchestration/drivers_orchestration.py b/.evergreen/orchestration/drivers_orchestration.py index 04c271990..1fa9d4827 100644 --- a/.evergreen/orchestration/drivers_orchestration.py +++ b/.evergreen/orchestration/drivers_orchestration.py @@ -188,7 +188,7 @@ def traverse(root): def normalize_path(path: Path | str) -> str: if os.name != "nt": return str(path) - path = path.as_posix() + path = Path(path).as_posix() return re.sub("/cygdrive/(.*?)(/)", r"\1://", path, count=1) From 6f178deb79499b612ba28bb0ad2bd835bf45e733 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 25 Feb 2025 17:22:46 -0600 Subject: [PATCH 11/11] fix python 3.9 support --- .evergreen/orchestration/drivers_orchestration.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.evergreen/orchestration/drivers_orchestration.py b/.evergreen/orchestration/drivers_orchestration.py index 1fa9d4827..e1ced16b9 100644 --- a/.evergreen/orchestration/drivers_orchestration.py +++ b/.evergreen/orchestration/drivers_orchestration.py @@ -4,6 +4,8 @@ Use '--help' for more information. """ +from __future__ import annotations + import argparse import json import logging