Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 59 additions & 16 deletions .evergreen/orchestration/drivers_orchestration.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
Use '--help' for more information.
"""

from __future__ import annotations

import argparse
import json
import logging
import os
import re
import shlex
import shutil
import socket
Expand Down Expand Up @@ -64,10 +67,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",
Expand Down Expand Up @@ -100,7 +103,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.
Expand Down Expand Up @@ -172,13 +187,20 @@ def traverse(root):
router["logpath"] = f"/tmp/mongodb-{item['port']}.log"


def normalize_path(path: Path | str) -> str:
if os.name != "nt":
return str(path)
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)
Expand All @@ -193,7 +215,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"
Expand Down Expand Up @@ -225,7 +247,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"
)
Expand All @@ -238,7 +260,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(": ", "="))

Expand Down Expand Up @@ -276,7 +298,18 @@ 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", normalize_path(opts.tls_pem_key_file))
text = text.replace(f"{base}/ca.pem", normalize_path(opts.tls_ca_file))
else:
text = text.replace(
"ABSOLUTE_PATH_REPLACEMENT_TOKEN", normalize_path(DRIVERS_TOOLS)
)
data = json.loads(text)

if opts.require_api_version:
Expand Down Expand Up @@ -364,14 +397,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:
Expand All @@ -381,10 +415,15 @@ 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"] = normalize_path(opts.tls_cert_key_file)

mo_start = datetime.now()

# Start the process.
Expand All @@ -399,7 +438,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!")
Expand Down Expand Up @@ -430,7 +473,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
Expand Down
15 changes: 9 additions & 6 deletions .evergreen/run-orchestration.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 <topology>/<orchestration_file>.json configuration.
# STORAGE_ENGINE Set to a non-empty string to use the <topology>/<storage_engine>.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 <topology>/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 <topology>/<orchestration_file>.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)
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also provide an example of using the CLI options?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The readme doesn't mention the CLI at all yet, I think that would be a separate effort.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we open a ticket for that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


```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=<path-to>/client.pem
export TLS_PEM_KEY_FILE=<path-to>/server.pem
export TLS_CA_FILE=<path-to>/ca.pem
```

## Linters and Formatters
Expand Down
Loading