Skip to content

Commit b65459e

Browse files
authored
DRIVERS-3119 Add options to provide certificate and CA files (#614)
1 parent 9cb568f commit b65459e

File tree

3 files changed

+73
-27
lines changed

3 files changed

+73
-27
lines changed

.evergreen/orchestration/drivers_orchestration.py

+59-16
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
Use '--help' for more information.
55
"""
66

7+
from __future__ import annotations
8+
79
import argparse
810
import json
911
import logging
1012
import os
13+
import re
1114
import shlex
1215
import shutil
1316
import socket
@@ -64,10 +67,10 @@ def get_options():
6467
)
6568

6669
other_group = parser.add_argument_group("Other options")
67-
parser.add_argument(
70+
other_group.add_argument(
6871
"--load-balancer", action="store_true", help="Whether to use a load balancer"
6972
)
70-
parser.add_argument(
73+
other_group.add_argument(
7174
"--skip-crypt-shared",
7275
action="store_true",
7376
help="Whether to skip installing crypt_shared lib",
@@ -100,7 +103,19 @@ def get_options():
100103
)
101104
other_group.add_argument(
102105
"--existing-binaries-dir",
103-
help="A directory containing existing mongodb binaries to use instead of downloading new ones.",
106+
help="A directory containing existing mongodb binaries to use instead of downloading new ones",
107+
)
108+
other_group.add_argument(
109+
"--tls-cert-key-file",
110+
help="A .pem to be used as the tlsCertificateKeyFile option in mongo-orchestration",
111+
)
112+
other_group.add_argument(
113+
"--tls-pem-key-file",
114+
help="A .pem file that contains the TLS certificate and key for the server",
115+
)
116+
other_group.add_argument(
117+
"--tls-ca-file",
118+
help="A .pem file that contains the root certificate chain for the server",
104119
)
105120

106121
# Get the options, and then allow environment variable overrides.
@@ -172,13 +187,20 @@ def traverse(root):
172187
router["logpath"] = f"/tmp/mongodb-{item['port']}.log"
173188

174189

190+
def normalize_path(path: Path | str) -> str:
191+
if os.name != "nt":
192+
return str(path)
193+
path = Path(path).as_posix()
194+
return re.sub("/cygdrive/(.*?)(/)", r"\1://", path, count=1)
195+
196+
175197
def run(opts):
176198
LOGGER.info("Running orchestration...")
177199

178200
# Clean up previous files.
179201
mdb_binaries = Path(opts.mongodb_binaries)
180-
# NOTE: in general, we need to use posix strings to avoid path escapes on cygwin.
181-
mdb_binaries_str = mdb_binaries.as_posix()
202+
# NOTE: in general, we need to normalize paths to account for cygwin/Windows.
203+
mdb_binaries_str = normalize_path(mdb_binaries)
182204
shutil.rmtree(mdb_binaries, ignore_errors=True)
183205
expansion_yaml = Path("mo-expansion.yml")
184206
expansion_yaml.unlink(missing_ok=True)
@@ -193,7 +215,7 @@ def run(opts):
193215
dl_start = datetime.now()
194216
version = opts.version
195217
cache_dir = DRIVERS_TOOLS / ".local/cache"
196-
cache_dir_str = cache_dir.as_posix()
218+
cache_dir_str = normalize_path(cache_dir)
197219
default_args = f"--out {mdb_binaries_str} --cache-dir {cache_dir_str} --retries 5"
198220
if opts.quiet:
199221
default_args += " -q"
@@ -225,7 +247,7 @@ def run(opts):
225247
# We download crypt_shared to DRIVERS_TOOLS so that it is on a different
226248
# path location than the other binaries, which is required for
227249
# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.md#via-bypassautoencryption
228-
args = default_args.replace(mdb_binaries_str, DRIVERS_TOOLS.as_posix())
250+
args = default_args.replace(mdb_binaries_str, normalize_path(DRIVERS_TOOLS))
229251
args += (
230252
f" --version {version} --strip-path-components 1 --component crypt_shared"
231253
)
@@ -238,7 +260,7 @@ def run(opts):
238260
if fname in expected:
239261
crypt_shared_path = DRIVERS_TOOLS / fname
240262
assert crypt_shared_path is not None
241-
crypt_text = f'CRYPT_SHARED_LIB_PATH: "{crypt_shared_path.as_posix()}"'
263+
crypt_text = f'CRYPT_SHARED_LIB_PATH: "{normalize_path(crypt_shared_path)}"'
242264
expansion_yaml.write_text(crypt_text)
243265
expansion_sh.write_text(crypt_text.replace(": ", "="))
244266

@@ -276,7 +298,18 @@ def run(opts):
276298
orch_path = mo_home / f"configs/{topology}s/{orchestration_file}"
277299
LOGGER.info(f"Using orchestration file: {orch_path}")
278300
text = orch_path.read_text()
279-
text = text.replace("ABSOLUTE_PATH_REPLACEMENT_TOKEN", DRIVERS_TOOLS.as_posix())
301+
302+
# Handle overriding the tls configuration in the file.
303+
if opts.tls_pem_key_file or opts.tls_ca_file:
304+
if not (opts.tls_pem_key_file and opts.tls_ca_file):
305+
raise ValueError("You must supply both tls-pem-key-file and tls-ca-file")
306+
base = "ABSOLUTE_PATH_REPLACEMENT_TOKEN/.evergreen/x509gen"
307+
text = text.replace(f"{base}/server.pem", normalize_path(opts.tls_pem_key_file))
308+
text = text.replace(f"{base}/ca.pem", normalize_path(opts.tls_ca_file))
309+
else:
310+
text = text.replace(
311+
"ABSOLUTE_PATH_REPLACEMENT_TOKEN", normalize_path(DRIVERS_TOOLS)
312+
)
280313
data = json.loads(text)
281314

282315
if opts.require_api_version:
@@ -364,14 +397,15 @@ def start(opts):
364397
os.makedirs(mo_home / "lib", exist_ok=True)
365398
mo_config = mo_home / "orchestration.config"
366399
mdb_binaries = Path(opts.mongodb_binaries)
367-
config = dict(releases=dict(default=mdb_binaries.as_posix()))
400+
config = dict(releases=dict(default=normalize_path(mdb_binaries)))
368401
mo_config.write_text(json.dumps(config, indent=2))
369-
mo_config_str = mo_config.as_posix()
370-
command = f"{sys.executable} -m mongo_orchestration.server"
402+
mo_config_str = normalize_path(mo_config)
403+
sys_executable = normalize_path(sys.executable)
404+
command = f"{sys_executable} -m mongo_orchestration.server"
371405

372406
# Handle Windows-specific concerns.
373407
if os.name == "nt":
374-
# Copy client certificates.
408+
# Copy default client certificate.
375409
src = DRIVERS_TOOLS / ".evergreen/x509gen/client.pem"
376410
dst = mo_home / "lib/client.pem"
377411
try:
@@ -381,10 +415,15 @@ def start(opts):
381415

382416
# We need to use the CLI executable, and add it to our path.
383417
os.environ["PATH"] = (
384-
f"{Path(sys.executable).parent}{os.pathsep}{os.environ['PATH']}"
418+
f"{Path(sys_executable).parent}{os.pathsep}{os.environ['PATH']}"
385419
)
386420
command = "mongo-orchestration -s wsgiref"
387421

422+
# Override the client cert file if applicable.
423+
env = os.environ.copy()
424+
if opts.tls_cert_key_file:
425+
env["MONGO_ORCHESTRATION_CLIENT_CERT"] = normalize_path(opts.tls_cert_key_file)
426+
388427
mo_start = datetime.now()
389428

390429
# Start the process.
@@ -399,7 +438,11 @@ def start(opts):
399438
output_fid = output_file.open("w")
400439
try:
401440
subprocess.run(
402-
shlex.split(args), check=True, stderr=subprocess.STDOUT, stdout=output_fid
441+
shlex.split(args),
442+
check=True,
443+
stderr=subprocess.STDOUT,
444+
stdout=output_fid,
445+
env=env,
403446
)
404447
except subprocess.CalledProcessError:
405448
LOGGER.error("Orchestration failed!")
@@ -430,7 +473,7 @@ def start(opts):
430473

431474
def stop():
432475
LOGGER.info("Stopping mongo-orchestration...")
433-
py_exe = Path(sys.executable).as_posix()
476+
py_exe = normalize_path(sys.executable)
434477
args = f"{py_exe} -m mongo_orchestration.server stop"
435478
proc = subprocess.run(
436479
shlex.split(args), check=True, stderr=subprocess.STDOUT, stdout=subprocess.PIPE

.evergreen/run-orchestration.sh

+9-6
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,20 @@ set -eu
66
# AUTH Set to "auth" to enable authentication. Defaults to "noauth"
77
# SSL Set to "yes" to enable SSL. Defaults to "nossl"
88
# TOPOLOGY Set to "server", "replica_set", or "sharded_cluster". Defaults to "server" (i.e. standalone).
9-
# LOAD_BALANCER Set to a non-empty string to enable load balancer. Only supported for sharded clusters.
9+
# MONGODB_VERSION Set the MongoDB version to use. Defaults to "latest".
10+
# MONGODB_DOWNLOAD_URL Set the MongoDB download URL to use for download-mongodb.sh.
11+
# ORCHESTRATION_FILE Set the <topology>/<orchestration_file>.json configuration.
1012
# STORAGE_ENGINE Set to a non-empty string to use the <topology>/<storage_engine>.json configuration (e.g. STORAGE_ENGINE=inmemory).
1113
# REQUIRE_API_VERSION Set to a non-empty string to set the requireApiVersion parameter. Currently only supported for standalone servers.
1214
# DISABLE_TEST_COMMANDS Set to a non-empty string to use the <topology>/disableTestCommands.json configuration (e.g. DISABLE_TEST_COMMANDS=1).
13-
# MONGODB_VERSION Set to a MongoDB version to use for download-mongodb.sh. Defaults to "latest".
14-
# MONGODB_DOWNLOAD_URL Set to a MongoDB download URL to use for download-mongodb.sh.
15-
# ORCHESTRATION_FILE Set to a non-empty string to use the <topology>/<orchestration_file>.json configuration.
1615
# SKIP_CRYPT_SHARED Set to a non-empty string to skip downloading crypt_shared
17-
# MONGODB_BINARIES Set to a non-empty string to set the path to the MONGODB_BINARIES for mongo orchestration.
18-
# PYTHON Set to a non-empty string to set the Python binary to use.
16+
# MONGODB_BINARIES Set the path to the MONGODB_BINARIES for mongo orchestration.
17+
# LOAD_BALANCER Set to a non-empty string to enable load balancer. Only supported for sharded clusters.
18+
# PYTHON Set the Python binary to use.
1919
# INSTALL_LEGACY_SHELL Set to a non-empty string to install the legacy mongo shell.
20+
# TLS_CERT_KEY_FILE Set a .pem file to be used as the tlsCertificateKeyFile option in mongo-orchestration
21+
# TLS_PEM_KEY_FILE Set a .pem file that contains the TLS certificate and key for the server
22+
# TLS_CA_FILE Set a .pem file that contains the root certificate chain for the server
2023

2124
# See https://stackoverflow.com/questions/35006457/choosing-between-0-and-bash-source/35006505#35006505
2225
# Why we need this syntax when sh is not aliased to bash (this script must be able to be called from sh)

README.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ There are two options for running a MongoDB server configuration.
8686
One is to use [docker](./.evergreen/docker/README.md).
8787
The other is to run `./evergreen/run-orchestration.sh` locally.
8888
For convenience, you can run `make run-server` and `make stop-server` to start and stop the server(s).
89+
8990
For example:
9091

9192
```bash
@@ -94,13 +95,12 @@ TOPOLOGY=replica_set MONGODB_VERSION=7.0 make run-server
9495

9596
See (run-orchestration.sh)[./evergreen/run-orchestration.sh] for the available environment variables.
9697

97-
In order to use custom certificates in your server, copy the client certificate file to
98-
`$MONGO_ORCHESTRATION_HOME/lib/client.pem` (where `MONGO_ORCHESTRATION_HOME`
99-
defaults to `$DRIVERS_TOOLS/.evergreen/orchestration`), e.g.
98+
In order to use custom certificates in your server, set the following environment variables:
10099

101100
```bash
102-
# Replace Mongo Orchestration's client certificate.
103-
cp ${PROJECT_DIRECTORY}/test/certificates/client.pem ${MONGO_ORCHESTRATION_HOME}/lib/client.pem
101+
export TLS_CERT_KEY_FILE=<path-to>/client.pem
102+
export TLS_PEM_KEY_FILE=<path-to>/server.pem
103+
export TLS_CA_FILE=<path-to>/ca.pem
104104
```
105105

106106
## Linters and Formatters

0 commit comments

Comments
 (0)