Skip to content

Commit

Permalink
SERVER-59012: Calculate FCV constants in resmoke
Browse files Browse the repository at this point in the history
  • Loading branch information
XueruiFa authored and Evergreen Agent committed Sep 20, 2021
1 parent d148373 commit efdac64
Show file tree
Hide file tree
Showing 26 changed files with 325 additions and 69 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,10 @@ resmoke.ini
# UndoDB Recordings
*.undo

# Resmoke runtime trackers
# Resmoke runtime configuration and trackers.
.resmoke_start_time.yml
.resmoke_mongo_version.yml
.resmoke_mongo_release_values.yml

# libfuzzer artifacts
default.profraw
Expand Down
2 changes: 1 addition & 1 deletion buildscripts/resmokeconfig/matrix_suites/tags.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""Dynamically Generated tags."""
from buildscripts.resmokelib.multiversionconstants import REQUIRES_FCV_TAG


# TODO SERVER-55857: Let this file be the single source of truth for tags. Remove dupe definitions.
Expand All @@ -10,6 +9,7 @@ class Tags(object):

BACKPORT_REQUIRED_TAG = "backport_required_multiversion"

from buildscripts.resmokelib.multiversionconstants import REQUIRES_FCV_TAG
# Base exclusion tag list.
EXCLUDE_TAGS_TEMPLATE = f"{REQUIRES_FCV_TAG},multiversion_incompatible,{BACKPORT_REQUIRED_TAG}"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,6 @@
#
# PLEASE DO NOT REMOVE ANYTHING, unless a build variant no longer runs in any Evergreen project.


evergreen_projects:
- mongodb-mongo-master
- mongodb-mongo-v5.0
- mongodb-mongo-v4.4
- mongodb-mongo-v4.2
- mongodb-mongo-v4.0


evergreen_buildvariants:
- name: ubuntu1604
edition: targeted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ selector:
- jstests/replsets/*.js
exclude_with_any_tags:
- multiversion_incompatible
# TODO (SERVER-55857): Remove this hardcoded tag once tests are filtered out using the
# 'REQUIRES_FCV_TAG' list in 'multiversion_constants.py'.
- requires_fcv_51
- backport_required_multiversion
- replica_sets_multiversion_backport_required_multiversion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ selector:
- jstests/sharding/change_streams/*.js
exclude_with_any_tags:
- multiversion_incompatible
# TODO (SERVER-55857): Remove this hardcoded tag once tests are filtered out using the
# 'REQUIRES_FCV_TAG' list in 'multiversion_constants.py'.
- requires_fcv_51
- backport_required_multiversion
- sharding_last_lts_mongos_and_mixed_shards_backport_required_multiversion
Expand Down
2 changes: 2 additions & 0 deletions buildscripts/resmokeconfig/suites/sharding_multiversion.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ selector:
- jstests/sharding/query/*.js
exclude_with_any_tags:
- multiversion_incompatible
# TODO (SERVER-55857): Remove this hardcoded tag once tests are filtered out using the
# 'REQUIRES_FCV_TAG' list in 'multiversion_constants.py'.
- requires_fcv_51
- backport_required_multiversion
- replica_sets_multiversion_backport_required_multiversion
Expand Down
1 change: 0 additions & 1 deletion buildscripts/resmokelib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from buildscripts.resmokelib import config
from buildscripts.resmokelib import errors
from buildscripts.resmokelib import logging
from buildscripts.resmokelib import multiversionconstants
from buildscripts.resmokelib import parser
from buildscripts.resmokelib import reportfile
from buildscripts.resmokelib import sighandler
Expand Down
52 changes: 52 additions & 0 deletions buildscripts/resmokelib/generate_fcv_constants/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""Generate FCV constants for consumption by non-C++ integration tests."""
import argparse

from buildscripts.resmokelib.plugin import PluginInterface, Subcommand

_COMMAND = "generate-fcv-constants"


class GenerateFCVConstants(Subcommand):
"""Interact with generating FCV constants."""

def __init__(self):
"""Constructor."""

def execute(self) -> None:
"""
Work your magic.
:return: None
"""
# This will cause multiversion constants to be generated.
import buildscripts.resmokelib.multiversionconstants # pylint: disable=unused-import
pass


class GenerateFCVConstantsPlugin(PluginInterface):
"""Interact with generating FCV constants."""

def add_subcommand(self, subparsers):
"""
Add 'generate-fcv-constants' subcommand.
:param subparsers: argparse parser to add to
:return: None
"""
# Can't hide this subcommand due to a Python bug. https://bugs.python.org/issue22848.
subparsers.add_parser(_COMMAND, help=argparse.SUPPRESS)

def parse(self, subcommand, parser, parsed_args, **kwargs):
"""
Return the FCV constants subcommand for execution.
:param subcommand: equivalent to parsed_args.command
:param parser: parser used
:param parsed_args: output of parsing
:param kwargs: additional args
:return: None or a Subcommand
"""
if subcommand != _COMMAND:
return None

return GenerateFCVConstants()
165 changes: 157 additions & 8 deletions buildscripts/resmokelib/multiversionconstants.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,154 @@
"""FCV and Server binary version constants used for multiversion testing."""
LAST_LTS_BIN_VERSION = "5.0"
LAST_CONTINUOUS_BIN_VERSION = "5.0"

LAST_LTS_FCV = "5.0"
LAST_CONTINUOUS_FCV = "5.0"
LATEST_FCV = "5.1"
from bisect import bisect_left, bisect_right
import os
import re
import shutil
from subprocess import call, CalledProcessError, check_output, STDOUT
import structlog
import yaml

from packaging.version import Version
from buildscripts.resmokelib.setup_multiversion.config import USE_EXISTING_RELEASES_FILE

LOGGER = structlog.getLogger(__name__)

# These values must match the include paths for artifacts.tgz in evergreen.yml.
MONGO_VERSION_YAML = ".resmoke_mongo_version.yml"
RELEASES_YAML = ".resmoke_mongo_release_values.yml"


def generate_mongo_version_file():
"""Generate the mongo version data file. Should only be called in the root of the mongo directory."""
try:
res = check_output("git describe", shell=True, text=True)
except CalledProcessError as exp:
raise ChildProcessError("Failed to run git describe to get the latest tag") from exp

# Write the current MONGO_VERSION to a data file.
with open(MONGO_VERSION_YAML, 'w') as mongo_version_fh:
# E.g. res = 'r5.1.0-alpha-597-g8c345c6693\n'
res = res[1:] # Remove the leading "r" character.
mongo_version_fh.write("mongo_version: " + res)


def generate_releases_file():
"""Generate the releases constants file."""
# Copy the 'releases.yml' file from the source tree.
releases_yaml_path = os.path.join("src", "mongo", "util", "version", "releases.yml")
if not os.path.isfile(releases_yaml_path):
LOGGER.info(
'Skipping yml file generation because file .resmoke_mongo_release_values.yml does not exist at path {}.'
.format(releases_yaml_path))
return

shutil.copyfile(releases_yaml_path, RELEASES_YAML)


def in_git_root_dir():
"""Return True if we are in the root of a git directory."""
if call(["git", "branch"], stderr=STDOUT, stdout=open(os.devnull, 'w')) != 0:
# We are not in a git directory.
return False

git_root_dir = check_output("git rev-parse --show-toplevel", shell=True, text=True).strip()
# Always use forward slash for the cwd path to resolve inconsistent formatting with Windows.
curr_dir = os.getcwd().replace("\\", "/")
return git_root_dir == curr_dir


if in_git_root_dir():
generate_mongo_version_file()
else:
LOGGER.info("Skipping generating mongo version file since we're not in the root of a git repo")

# Avoiding regenerating the releases file if this flag is set. Should only be set if there are
# multiple processes attempting to set up multiversion concurrently.
if not USE_EXISTING_RELEASES_FILE:
generate_releases_file()
else:
LOGGER.info(
"Skipping generating releases file since the --useExistingReleasesFile flag has been set")


class FCVConstantValues(object):
"""Object to hold the calculated FCV constants."""

def __init__(self, latest, last_continuous, last_lts, requires_fcv_tag_list,
fcvs_less_than_latest):
"""
Initialize the object.
:param latest: Latest FCV.
:param last_continuous: Last continuous FCV.
:param last_lts: Last LTS FCV.
:param requires_fcv_tag_list: List of FCVs that we need to generate a tag for.
:param fcvs_less_than_latest: List of all FCVs that are less than latest, starting from v4.0.
"""
self.latest = latest
self.last_continuous = last_continuous
self.last_lts = last_lts
self.requires_fcv_tag_list = requires_fcv_tag_list
self.fcvs_less_than_latest = fcvs_less_than_latest


def calculate_fcv_constants():
"""Calculate multiversion constants from data files."""
mongo_version_yml_file = open(MONGO_VERSION_YAML, 'r')
mongo_version_yml = yaml.safe_load(mongo_version_yml_file)
mongo_version = mongo_version_yml['mongo_version']
latest = Version(re.match(r'^[0-9]+\.[0-9]+', mongo_version).group(0))

releases_yml_file = open(RELEASES_YAML, 'r')
releases_yml = yaml.safe_load(releases_yml_file)

fcvs = releases_yml['featureCompatibilityVersions']
fcvs = list(map(Version, fcvs))
lts = releases_yml['longTermSupportReleases']
lts = list(map(Version, lts))

mongo_version_yml_file.close()
releases_yml_file.close()

# Highest release less than latest.
last_continuous = fcvs[bisect_left(fcvs, latest) - 1]

# Highest LTS release less than latest.
last_lts = lts[bisect_left(lts, latest) - 1]

# All FCVs greater than last LTS, up to latest.
requires_fcv_tag_list = fcvs[bisect_right(fcvs, last_lts):bisect_right(fcvs, latest)]

# All FCVs less than latest.
fcvs_less_than_latest = fcvs[:bisect_left(fcvs, latest)]

return FCVConstantValues(latest, last_continuous, last_lts, requires_fcv_tag_list,
fcvs_less_than_latest)


def version_str(version):
"""Return a string of the given version in 'MAJOR.MINOR' form."""
return '{}.{}'.format(version.major, version.minor)


def tag_str(version):
"""Return a tag for the given version."""
return 'requires_fcv_{}{}'.format(version.major, version.minor)


def evg_project_str(version):
"""Return the evergreen project name for the given version."""
return 'mongodb-mongo-v{}.{}'.format(version.major, version.minor)


fcv_constants = calculate_fcv_constants()

LAST_LTS_BIN_VERSION = version_str(fcv_constants.last_lts)
LAST_CONTINUOUS_BIN_VERSION = version_str(fcv_constants.last_continuous)

LAST_LTS_FCV = version_str(fcv_constants.last_lts)
LAST_CONTINUOUS_FCV = version_str(fcv_constants.last_continuous)
LATEST_FCV = version_str(fcv_constants.latest)

LAST_CONTINUOUS_MONGO_BINARY = "mongo-" + LAST_CONTINUOUS_BIN_VERSION
LAST_CONTINUOUS_MONGOD_BINARY = "mongod-" + LAST_CONTINUOUS_BIN_VERSION
Expand All @@ -14,7 +158,12 @@
LAST_LTS_MONGOD_BINARY = "mongod-" + LAST_LTS_BIN_VERSION
LAST_LTS_MONGOS_BINARY = "mongos-" + LAST_LTS_BIN_VERSION

REQUIRES_FCV_TAG_LATEST = "requires_fcv_51"
REQUIRES_FCV_TAG_LATEST = tag_str(fcv_constants.latest)

# Generate tags for all FCVS in (lastLTS, latest].
# All multiversion tests should be run with these tags excluded.
REQUIRES_FCV_TAG = ",".join([tag_str(fcv) for fcv in fcv_constants.requires_fcv_tag_list])

# TODO: rename this to REQUIRES_FCV_TAGS (plural) when `requires_fcv_52` is added to it.
REQUIRES_FCV_TAG = REQUIRES_FCV_TAG_LATEST
# Generate evergreen project names for all FCVs less than latest.
EVERGREEN_PROJECTS = ['mongodb-mongo-master']
EVERGREEN_PROJECTS.extend([evg_project_str(fcv) for fcv in fcv_constants.fcvs_less_than_latest])
2 changes: 2 additions & 0 deletions buildscripts/resmokelib/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import shlex

from buildscripts.resmokelib import configure_resmoke
from buildscripts.resmokelib.generate_fcv_constants import GenerateFCVConstantsPlugin
from buildscripts.resmokelib.hang_analyzer import HangAnalyzerPlugin
from buildscripts.resmokelib.powercycle import PowercyclePlugin
from buildscripts.resmokelib.run import RunPlugin
Expand All @@ -20,6 +21,7 @@
PowercyclePlugin(),
SymbolizerPlugin(),
BisectPlugin(),
GenerateFCVConstantsPlugin(),
]


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import requests

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
Expand Down Expand Up @@ -88,6 +87,8 @@ def generate_exclude_yaml(old_bin_version: str, output: str, logger: logging.Log
# Get the state of the backports_required_for_multiversion_tests.yml file for the old
# binary we are running tests against. We do this by using the commit hash from the old
# mongo shell executable.
from buildscripts.resmokelib import multiversionconstants

shell_version = {
MultiversionOptions.LAST_LTS: multiversionconstants.LAST_LTS_MONGO_BINARY,
MultiversionOptions.LAST_CONTINUOUS: multiversionconstants.LAST_CONTINUOUS_MONGO_BINARY,
Expand Down
2 changes: 2 additions & 0 deletions buildscripts/resmokelib/setup_multiversion/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
# Records the paths of installed multiversion binaries on Windows.
WINDOWS_BIN_PATHS_FILE = "windows_binary_paths.txt"

USE_EXISTING_RELEASES_FILE = False


class Buildvariant:
"""Class represents buildvariant in setup multiversion config."""
Expand Down
Loading

0 comments on commit efdac64

Please sign in to comment.