4
4
Use '--help' for more information.
5
5
"""
6
6
7
+ from __future__ import annotations
8
+
7
9
import argparse
8
10
import json
9
11
import logging
10
12
import os
13
+ import re
11
14
import shlex
12
15
import shutil
13
16
import socket
@@ -64,10 +67,10 @@ def get_options():
64
67
)
65
68
66
69
other_group = parser .add_argument_group ("Other options" )
67
- parser .add_argument (
70
+ other_group .add_argument (
68
71
"--load-balancer" , action = "store_true" , help = "Whether to use a load balancer"
69
72
)
70
- parser .add_argument (
73
+ other_group .add_argument (
71
74
"--skip-crypt-shared" ,
72
75
action = "store_true" ,
73
76
help = "Whether to skip installing crypt_shared lib" ,
@@ -100,7 +103,19 @@ def get_options():
100
103
)
101
104
other_group .add_argument (
102
105
"--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" ,
104
119
)
105
120
106
121
# Get the options, and then allow environment variable overrides.
@@ -172,13 +187,20 @@ def traverse(root):
172
187
router ["logpath" ] = f"/tmp/mongodb-{ item ['port' ]} .log"
173
188
174
189
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
+
175
197
def run (opts ):
176
198
LOGGER .info ("Running orchestration..." )
177
199
178
200
# Clean up previous files.
179
201
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 )
182
204
shutil .rmtree (mdb_binaries , ignore_errors = True )
183
205
expansion_yaml = Path ("mo-expansion.yml" )
184
206
expansion_yaml .unlink (missing_ok = True )
@@ -193,7 +215,7 @@ def run(opts):
193
215
dl_start = datetime .now ()
194
216
version = opts .version
195
217
cache_dir = DRIVERS_TOOLS / ".local/cache"
196
- cache_dir_str = cache_dir . as_posix ( )
218
+ cache_dir_str = normalize_path ( cache_dir )
197
219
default_args = f"--out { mdb_binaries_str } --cache-dir { cache_dir_str } --retries 5"
198
220
if opts .quiet :
199
221
default_args += " -q"
@@ -225,7 +247,7 @@ def run(opts):
225
247
# We download crypt_shared to DRIVERS_TOOLS so that it is on a different
226
248
# path location than the other binaries, which is required for
227
249
# 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 ))
229
251
args += (
230
252
f" --version { version } --strip-path-components 1 --component crypt_shared"
231
253
)
@@ -238,7 +260,7 @@ def run(opts):
238
260
if fname in expected :
239
261
crypt_shared_path = DRIVERS_TOOLS / fname
240
262
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 )} "'
242
264
expansion_yaml .write_text (crypt_text )
243
265
expansion_sh .write_text (crypt_text .replace (": " , "=" ))
244
266
@@ -276,7 +298,18 @@ def run(opts):
276
298
orch_path = mo_home / f"configs/{ topology } s/{ orchestration_file } "
277
299
LOGGER .info (f"Using orchestration file: { orch_path } " )
278
300
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
+ )
280
313
data = json .loads (text )
281
314
282
315
if opts .require_api_version :
@@ -364,14 +397,15 @@ def start(opts):
364
397
os .makedirs (mo_home / "lib" , exist_ok = True )
365
398
mo_config = mo_home / "orchestration.config"
366
399
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 )))
368
401
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"
371
405
372
406
# Handle Windows-specific concerns.
373
407
if os .name == "nt" :
374
- # Copy client certificates .
408
+ # Copy default client certificate .
375
409
src = DRIVERS_TOOLS / ".evergreen/x509gen/client.pem"
376
410
dst = mo_home / "lib/client.pem"
377
411
try :
@@ -381,10 +415,15 @@ def start(opts):
381
415
382
416
# We need to use the CLI executable, and add it to our path.
383
417
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' ]} "
385
419
)
386
420
command = "mongo-orchestration -s wsgiref"
387
421
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
+
388
427
mo_start = datetime .now ()
389
428
390
429
# Start the process.
@@ -399,7 +438,11 @@ def start(opts):
399
438
output_fid = output_file .open ("w" )
400
439
try :
401
440
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 ,
403
446
)
404
447
except subprocess .CalledProcessError :
405
448
LOGGER .error ("Orchestration failed!" )
@@ -430,7 +473,7 @@ def start(opts):
430
473
431
474
def stop ():
432
475
LOGGER .info ("Stopping mongo-orchestration..." )
433
- py_exe = Path (sys .executable ). as_posix ( )
476
+ py_exe = normalize_path (sys .executable )
434
477
args = f"{ py_exe } -m mongo_orchestration.server stop"
435
478
proc = subprocess .run (
436
479
shlex .split (args ), check = True , stderr = subprocess .STDOUT , stdout = subprocess .PIPE
0 commit comments