summaryrefslogtreecommitdiff
path: root/buildscripts
diff options
context:
space:
mode:
authorRobert Guo <robert.guo@mongodb.com>2021-08-01 23:14:07 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-08-04 11:54:43 +0000
commite74e88defab5d9081e4e3d81bd2457b04c32af48 (patch)
tree48e7ad8fecfe8c7e1810c0dffd9c88ac853764ae /buildscripts
parentf0defdba5d5839e4cbfd3b0fa69fb8369419ded4 (diff)
downloadmongo-e74e88defab5d9081e4e3d81bd2457b04c32af48.tar.gz
SERVER-58126 Avoid symlinking downloaded binaries on Windows
Diffstat (limited to 'buildscripts')
-rw-r--r--buildscripts/resmokelib/config.py7
-rw-r--r--buildscripts/resmokelib/core/programs.py5
-rw-r--r--buildscripts/resmokelib/hang_analyzer/extractor.py11
-rwxr-xr-xbuildscripts/resmokelib/powercycle/powercycle.py1
-rwxr-xr-xbuildscripts/resmokelib/run/generate_multiversion_exclude_tags.py22
-rw-r--r--buildscripts/resmokelib/setup_multiversion/config.py3
-rw-r--r--buildscripts/resmokelib/setup_multiversion/download.py33
-rw-r--r--buildscripts/resmokelib/setup_multiversion/setup_multiversion.py49
-rw-r--r--buildscripts/resmokelib/symbolizer/__init__.py5
-rw-r--r--buildscripts/resmokelib/utils/filesystem.py14
-rw-r--r--buildscripts/tests/resmokelib/setup_multiversion/test_setup_multiversion.py2
11 files changed, 108 insertions, 44 deletions
diff --git a/buildscripts/resmokelib/config.py b/buildscripts/resmokelib/config.py
index ca9e82e055c..9272fbf52b9 100644
--- a/buildscripts/resmokelib/config.py
+++ b/buildscripts/resmokelib/config.py
@@ -6,6 +6,8 @@ import itertools
import os.path
import time
+import buildscripts.resmokelib.setup_multiversion.config as multiversion_config
+
# Subdirectory under the dbpath prefix that contains directories with data files of mongod's started
# by resmoke.py.
FIXTURE_SUBDIR = "resmoke"
@@ -37,7 +39,10 @@ DEFAULT_DBPATH_PREFIX = os.path.normpath("/data/db")
# Default directory that we expect to contain binaries for multiversion testing. This directory is
# added to the PATH when calling programs.make_process().
-DEFAULT_MULTIVERSION_DIR = os.path.normpath("/data/multiversion")
+DEFAULT_MULTIVERSION_DIRS = [os.path.normpath("/data/multiversion")]
+if os.path.isfile(multiversion_config.WINDOWS_BIN_PATHS_FILE):
+ with open(multiversion_config.WINDOWS_BIN_PATHS_FILE) as wbpf:
+ DEFAULT_MULTIVERSION_DIRS.extend(wbpf.read().split(os.pathsep))
# Default location for the genny executable. Override this in the YAML suite configuration if
# desired.
diff --git a/buildscripts/resmokelib/core/programs.py b/buildscripts/resmokelib/core/programs.py
index a2d6b3fd5fd..b4aaae953db 100644
--- a/buildscripts/resmokelib/core/programs.py
+++ b/buildscripts/resmokelib/core/programs.py
@@ -42,10 +42,7 @@ def make_process(*args, **kwargs):
def get_path_env_var(env_vars):
"""Return the path base on provided environment variable."""
- path = [
- os.getcwd(),
- config.DEFAULT_MULTIVERSION_DIR,
- ]
+ path = [os.getcwd()] + config.DEFAULT_MULTIVERSION_DIRS
# If installDir is provided, add it early to the path
if config.INSTALL_DIR is not None:
path.append(config.INSTALL_DIR)
diff --git a/buildscripts/resmokelib/hang_analyzer/extractor.py b/buildscripts/resmokelib/hang_analyzer/extractor.py
index 01e1fd54fb5..70574e59dcc 100644
--- a/buildscripts/resmokelib/hang_analyzer/extractor.py
+++ b/buildscripts/resmokelib/hang_analyzer/extractor.py
@@ -2,6 +2,7 @@
import glob
import os
+import platform
import shutil
import tarfile
import time
@@ -9,6 +10,8 @@ import time
from buildscripts.resmokelib import config
from buildscripts.resmokelib.run import compare_start_time
from buildscripts.resmokelib.setup_multiversion.setup_multiversion import SetupMultiversion
+from buildscripts.resmokelib.utils import is_windows
+from buildscripts.resmokelib.utils.filesystem import build_hygienic_bin_path
_DEBUG_FILE_BASE_NAMES = ['mongo', 'mongod', 'mongos']
@@ -65,7 +68,7 @@ def _extracted_files_to_copy():
out = []
for ext in ['debug', 'dSYM', 'pdb']:
for file in _DEBUG_FILE_BASE_NAMES:
- haystack = os.path.join('dist-test', 'bin', '{file}.{ext}'.format(file=file, ext=ext))
+ haystack = build_hygienic_bin_path(child='{file}.{ext}'.format(file=file, ext=ext))
for needle in glob.glob(haystack):
out.append((needle, os.path.join(os.getcwd(), os.path.basename(needle))))
return out
@@ -77,11 +80,11 @@ def download_debug_symbols(root_logger, download_url):
while True:
try:
+ install_dir_list = []
SetupMultiversion.setup_mongodb(artifacts_url=None, binaries_url=None,
- symbols_url=download_url, install_dir=os.getcwd())
-
+ symbols_url=download_url, install_dir=os.getcwd(),
+ install_dir_list=install_dir_list)
break
-
except tarfile.ReadError:
root_logger.info("Debug symbols unavailable after %s secs, retrying in %s secs",
compare_start_time(time.time()), retry_secs)
diff --git a/buildscripts/resmokelib/powercycle/powercycle.py b/buildscripts/resmokelib/powercycle/powercycle.py
index c493ac7c22a..cdaa9125bd7 100755
--- a/buildscripts/resmokelib/powercycle/powercycle.py
+++ b/buildscripts/resmokelib/powercycle/powercycle.py
@@ -36,6 +36,7 @@ from buildscripts.resmokelib.powercycle import powercycle_config, powercycle_con
# See https://docs.python.org/2/library/sys.html#sys.platform
from buildscripts.resmokelib.powercycle.lib.services import WindowsService, PosixService
+from buildscripts.resmokelib.utils.filesystem import build_hygienic_bin_path
_IS_WINDOWS = sys.platform == "win32" or sys.platform == "cygwin"
_IS_LINUX = sys.platform.startswith("linux")
diff --git a/buildscripts/resmokelib/run/generate_multiversion_exclude_tags.py b/buildscripts/resmokelib/run/generate_multiversion_exclude_tags.py
index e42d3c83aa6..b26159e3b65 100755
--- a/buildscripts/resmokelib/run/generate_multiversion_exclude_tags.py
+++ b/buildscripts/resmokelib/run/generate_multiversion_exclude_tags.py
@@ -2,11 +2,9 @@
import logging
import os
import re
-import sys
import tempfile
from collections import defaultdict
from subprocess import check_output
-from sys import platform
import requests
@@ -14,6 +12,7 @@ from buildscripts.ciconfig import tags as _tags
from buildscripts.resmokelib import multiversionconstants
from buildscripts.resmokelib.config import MultiversionOptions
from buildscripts.resmokelib.core.programs import get_path_env_var
+from buildscripts.resmokelib.utils import is_windows
from buildscripts.util.fileops import read_yaml_file
BACKPORT_REQUIRED_TAG = "backport_required_multiversion"
@@ -26,15 +25,16 @@ BACKPORTS_REQUIRED_BASE_URL = "https://raw.githubusercontent.com/mongodb/mongo"
def get_backports_required_hash_for_shell_version(mongo_shell_path=None):
"""Parse the old shell binary to get the commit hash."""
- env_vars = {}
- path = get_path_env_var(env_vars=env_vars)
- env_vars["PATH"] = os.pathsep.join(path)
-
- if platform.startswith("win"):
- shell_version = check_output([mongo_shell_path + ".exe", "--version"],
- env=env_vars).decode('utf-8')
- else:
- shell_version = check_output([mongo_shell_path, "--version"], env=env_vars).decode('utf-8')
+ env_vars = os.environ.copy()
+ paths = get_path_env_var(env_vars=env_vars)
+ env_vars["PATH"] = os.pathsep.join(paths)
+
+ mongo_shell = mongo_shell_path
+ if is_windows():
+ mongo_shell = mongo_shell_path + ".exe"
+
+ shell_version = check_output(f"{mongo_shell} --version", shell=True,
+ env=env_vars).decode('utf-8')
for line in shell_version.splitlines():
if "gitVersion" in line:
version_line = line.split(':')[1]
diff --git a/buildscripts/resmokelib/setup_multiversion/config.py b/buildscripts/resmokelib/setup_multiversion/config.py
index f2c63921ef3..e81fd445f58 100644
--- a/buildscripts/resmokelib/setup_multiversion/config.py
+++ b/buildscripts/resmokelib/setup_multiversion/config.py
@@ -3,6 +3,9 @@ from typing import List
SETUP_MULTIVERSION_CONFIG = "buildscripts/resmokeconfig/setup_multiversion/setup_multiversion_config.yml"
+# Records the paths of installed multiversion binaries on Windows.
+WINDOWS_BIN_PATHS_FILE = "windows_binary_paths.txt"
+
class Buildvariant:
"""Class represents buildvariant in setup multiversion config."""
diff --git a/buildscripts/resmokelib/setup_multiversion/download.py b/buildscripts/resmokelib/setup_multiversion/download.py
index fa145bf2a76..ec0c5e8833d 100644
--- a/buildscripts/resmokelib/setup_multiversion/download.py
+++ b/buildscripts/resmokelib/setup_multiversion/download.py
@@ -11,7 +11,7 @@ import zipfile
import requests
import structlog
-from buildscripts.resmokelib.utils.filesystem import mkdtemp_in_build_dir
+from buildscripts.resmokelib.utils.filesystem import mkdtemp_in_build_dir, build_hygienic_bin_path
S3_BUCKET = "mciuploads"
@@ -104,23 +104,38 @@ def extract_archive(archive_file, install_dir):
return install_dir
-def symlink_version(suffix, installed_dir, link_dir):
- """Symlink the binaries in the 'installed_dir' to the 'link_dir'."""
+def mkdir_p(path):
+ """Python equivalent of `mkdir -p`."""
try:
- os.makedirs(link_dir)
+ os.makedirs(path)
except OSError as exc:
- if exc.errno == errno.EEXIST and os.path.isdir(link_dir):
+ if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
- hygienic_bin_dir = os.path.join(installed_dir, "dist-test", "bin")
+
+def symlink_version(suffix, installed_dir, link_dir=None):
+ """
+ Symlink the binaries in the 'installed_dir' to the 'link_dir'.
+
+ If `link_dir` is None, link to the physical executable's directory (`bin_dir`).
+ """
+ hygienic_bin_dir = build_hygienic_bin_path(parent=installed_dir)
if os.path.isdir(hygienic_bin_dir):
bin_dir = hygienic_bin_dir
else:
bin_dir = installed_dir
+ if link_dir is None:
+ link_dir = bin_dir
+ else:
+ mkdir_p(link_dir)
+
for executable in os.listdir(bin_dir):
+ if executable.endswith(".dll"):
+ LOGGER.debug("Skipping linking DLL", file=executable)
+ continue
executable_name, executable_extension = os.path.splitext(executable)
if suffix:
@@ -132,6 +147,7 @@ def symlink_version(suffix, installed_dir, link_dir):
executable = os.path.join(bin_dir, executable)
executable_link = os.path.join(link_dir, link_name)
+ link_method = os.symlink
if os.name == "nt":
# os.symlink is not supported on Windows, use a direct method instead.
def symlink_ms(source, symlink_name):
@@ -144,8 +160,8 @@ def symlink_version(suffix, installed_dir, link_dir):
if csl(symlink_name, source.replace("/", "\\"), flags) == 0:
raise ctypes.WinError()
- os.symlink = symlink_ms
- os.symlink(executable, executable_link)
+ link_method = symlink_ms
+ link_method(executable, executable_link)
LOGGER.debug("Symlink created.", executable=executable, executable_link=executable_link)
except OSError as exc:
@@ -155,3 +171,4 @@ def symlink_version(suffix, installed_dir, link_dir):
raise
LOGGER.info("Symlinks for all executables are created in the directory.", link_dir=link_dir)
+ return link_dir
diff --git a/buildscripts/resmokelib/setup_multiversion/setup_multiversion.py b/buildscripts/resmokelib/setup_multiversion/setup_multiversion.py
index 2e24cbd40eb..6fa0116ae21 100644
--- a/buildscripts/resmokelib/setup_multiversion/setup_multiversion.py
+++ b/buildscripts/resmokelib/setup_multiversion/setup_multiversion.py
@@ -16,7 +16,7 @@ import yaml
from buildscripts.resmokelib.plugin import PluginInterface, Subcommand
from buildscripts.resmokelib.setup_multiversion import config, download, github_conn
-from buildscripts.resmokelib.utils import evergreen_conn
+from buildscripts.resmokelib.utils import evergreen_conn, is_windows
SUBCOMMAND = "setup-multiversion"
@@ -44,17 +44,17 @@ class SetupMultiversion(Subcommand):
"""Main class for the setup multiversion subcommand."""
# pylint: disable=too-many-instance-attributes
- def __init__(self, download_options, install_dir="", link_dir="", platform=None, edition=None,
- architecture=None, use_latest=None, versions=None, evergreen_config=None,
- github_oauth_token=None, debug=None, ignore_failed_push=False):
+ def __init__(self, download_options, install_dir="", link_dir="", mv_platform=None,
+ edition=None, architecture=None, use_latest=None, versions=None,
+ evergreen_config=None, github_oauth_token=None, debug=None,
+ ignore_failed_push=False):
"""Initialize."""
setup_logging(debug)
- cwd = os.getcwd()
- self.install_dir = os.path.join(cwd, install_dir)
- self.link_dir = os.path.join(cwd, link_dir)
+ self.install_dir = os.path.abspath(install_dir)
+ self.link_dir = os.path.abspath(link_dir)
self.edition = edition.lower() if edition else None
- self.platform = platform.lower() if platform else None
+ self.platform = mv_platform.lower() if mv_platform else None
self.architecture = architecture.lower() if architecture else None
self.use_latest = use_latest
self.versions = versions
@@ -72,6 +72,9 @@ class SetupMultiversion(Subcommand):
raw_yaml = yaml.safe_load(file_handle)
self.config = config.SetupMultiversionConfig(raw_yaml)
+ self._is_windows = is_windows()
+ self._windows_bin_install_dirs = []
+
@staticmethod
def _get_bin_suffix(version, evg_project_id):
"""Get the multiversion bin suffix from the evergreen project ID."""
@@ -108,7 +111,6 @@ class SetupMultiversion(Subcommand):
install_dir = os.path.join(self.install_dir, version)
self.download_and_extract_from_urls(urls, bin_suffix, install_dir)
-
except (github_conn.GithubConnError, evergreen_conn.EvergreenConnError,
download.DownloadError) as ex:
LOGGER.error(ex)
@@ -130,7 +132,18 @@ class SetupMultiversion(Subcommand):
download_symbols_url = urls.get(" mongo-debugsymbols.zip", None)
self.setup_mongodb(artifacts_url, binaries_url, download_symbols_url, install_dir,
- bin_suffix, self.link_dir)
+ bin_suffix, link_dir=self.link_dir,
+ install_dir_list=self._windows_bin_install_dirs)
+
+ if self._is_windows:
+ self._write_windows_install_paths(self._windows_bin_install_dirs)
+
+ @staticmethod
+ def _write_windows_install_paths(paths):
+ with open(config.WINDOWS_BIN_PATHS_FILE, "w") as out:
+ out.write(os.pathsep.join(paths))
+
+ LOGGER.info(f"Finished writing binary paths on Windows to {config.WINDOWS_BIN_PATHS_FILE}")
def get_latest_urls(self, version):
"""Return latest urls."""
@@ -204,7 +217,7 @@ class SetupMultiversion(Subcommand):
@staticmethod
def setup_mongodb(artifacts_url, binaries_url, symbols_url, install_dir, bin_suffix=None,
- link_dir=None):
+ link_dir=None, install_dir_list=None):
# pylint: disable=too-many-arguments
"""Download, extract and symlink."""
@@ -225,7 +238,17 @@ class SetupMultiversion(Subcommand):
try_download(url)
if binaries_url is not None:
- download.symlink_version(bin_suffix, install_dir, link_dir)
+ if not link_dir:
+ raise ValueError("link_dir must be specified if downloading binaries")
+
+ if not is_windows():
+ link_dir = download.symlink_version(bin_suffix, install_dir, link_dir)
+ else:
+ LOGGER.info(
+ "Linking to install_dir on Windows; executable have to live in different working"
+ " directories to avoid DLLs for different versions clobbering each other")
+ link_dir = download.symlink_version(bin_suffix, install_dir, None)
+ install_dir_list.append(link_dir)
def get_buildvariant_name(self, major_minor_version):
"""Return buildvariant name.
@@ -269,7 +292,7 @@ class SetupMultiversionPlugin(PluginInterface):
da=args.download_artifacts)
return SetupMultiversion(install_dir=args.install_dir, link_dir=args.link_dir,
- platform=args.platform, edition=args.edition,
+ mv_platform=args.platform, edition=args.edition,
architecture=args.architecture, use_latest=args.use_latest,
versions=args.versions, download_options=download_options,
evergreen_config=args.evergreen_config,
diff --git a/buildscripts/resmokelib/symbolizer/__init__.py b/buildscripts/resmokelib/symbolizer/__init__.py
index d12aa264bf5..54111cff5f6 100644
--- a/buildscripts/resmokelib/symbolizer/__init__.py
+++ b/buildscripts/resmokelib/symbolizer/__init__.py
@@ -12,6 +12,7 @@ from buildscripts import mongosymb
from buildscripts.resmokelib.plugin import PluginInterface, Subcommand
from buildscripts.resmokelib.setup_multiversion.setup_multiversion import SetupMultiversion, _DownloadOptions
from buildscripts.resmokelib.utils import evergreen_conn
+from buildscripts.resmokelib.utils.filesystem import build_hygienic_bin_path
_HELP = """
Symbolize a backtrace JSON file given an Evergreen Task ID.
@@ -151,8 +152,8 @@ class Symbolizer(Subcommand):
raise ValueError(f"Must not specify path_to_executable, the original path that "
f"generated the symbols will be used: {sym_search_path}")
# TODO: support non-hygienic builds.
- self.mongosym_args.path_to_executable = os.path.join(self.dest_dir, "dist-test", "bin",
- self.bin_name)
+ self.mongosym_args.path_to_executable = build_hygienic_bin_path(
+ parent=self.dest_dir, child=self.bin_name)
self.mongosym_args.src_dir_to_move = self.dest_dir
diff --git a/buildscripts/resmokelib/utils/filesystem.py b/buildscripts/resmokelib/utils/filesystem.py
index 0cc8decb1b8..945c8312201 100644
--- a/buildscripts/resmokelib/utils/filesystem.py
+++ b/buildscripts/resmokelib/utils/filesystem.py
@@ -23,3 +23,17 @@ def remove_if_exists(path):
def is_yaml_file(filename):
"""Return true if 'filename' ends in .yml or .yaml, and false otherwise."""
return os.path.splitext(filename)[1] in (".yaml", ".yml")
+
+
+def build_hygienic_bin_path(parent=None, child=None):
+ """Get the hygienic bin directory, optionally from `parent` and with `child`."""
+ pjoin = os.path.join
+ res = pjoin("dist-test", "bin")
+
+ if parent:
+ res = pjoin(parent, res)
+
+ if child:
+ res = pjoin(res, child)
+
+ return res
diff --git a/buildscripts/tests/resmokelib/setup_multiversion/test_setup_multiversion.py b/buildscripts/tests/resmokelib/setup_multiversion/test_setup_multiversion.py
index 24786de4ac7..9365238172c 100644
--- a/buildscripts/tests/resmokelib/setup_multiversion/test_setup_multiversion.py
+++ b/buildscripts/tests/resmokelib/setup_multiversion/test_setup_multiversion.py
@@ -43,7 +43,7 @@ class TestSetupMultiversionBase(unittest.TestCase):
install_dir="install",
link_dir="link",
edition=edition,
- platform=platform,
+ mv_platform=platform,
architecture=architecture,
use_latest=False,
versions=["4.2.1"],