44Use '--help' for more information.
55"""
66
7+ from __future__ import annotations
8+
79import argparse
810import json
911import logging
1012import os
13+ import re
1114import shlex
1215import shutil
1316import 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+
175197def 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
431474def 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
0 commit comments