225 lines
7.4 KiB
Python
225 lines
7.4 KiB
Python
import copy
|
|
import os
|
|
import shlex
|
|
from typing import Any, Dict, List, Optional, Tuple
|
|
|
|
from ray_release.aws import RELEASE_AWS_BUCKET
|
|
from ray_release.buildkite.concurrency import get_concurrency_group
|
|
from ray_release.config import (
|
|
DEFAULT_ANYSCALE_PROJECT,
|
|
DEFAULT_CLOUD_ID,
|
|
DEFAULT_CLOUD_NAME,
|
|
as_smoke_test,
|
|
get_test_project_id,
|
|
)
|
|
from ray_release.custom_byod_build_init_helper import (
|
|
generate_custom_build_step_key,
|
|
get_prerequisite_step,
|
|
)
|
|
from ray_release.env import DEFAULT_ENVIRONMENT, load_environment
|
|
from ray_release.template import get_test_env_var
|
|
from ray_release.test import Test, TestState
|
|
from ray_release.util import DeferredEnvVar
|
|
|
|
DEFAULT_ARTIFACTS_DIR_HOST = "/tmp/ray_release_test_artifacts"
|
|
|
|
# TODO (can): unify release_queue_small and runner_queue_small_branch queues
|
|
# having too many type of queues make them difficult to maintain
|
|
RELEASE_QUEUE_DEFAULT = DeferredEnvVar("RELEASE_QUEUE_DEFAULT", "release_queue_small")
|
|
RELEASE_QUEUE_CLIENT = DeferredEnvVar("RELEASE_QUEUE_CLIENT", "release_queue_small")
|
|
|
|
DOCKER_PLUGIN_KEY = "docker#v5.8.0"
|
|
|
|
_DEFAULT_STEP_TEMPLATE: Dict[str, Any] = {
|
|
"env": {
|
|
"ANYSCALE_CLOUD_ID": str(DEFAULT_CLOUD_ID),
|
|
"ANYSCALE_CLOUD_NAME": str(DEFAULT_CLOUD_NAME),
|
|
"ANYSCALE_PROJECT": str(DEFAULT_ANYSCALE_PROJECT),
|
|
"RELEASE_AWS_BUCKET": str(RELEASE_AWS_BUCKET),
|
|
"RELEASE_AWS_LOCATION": "dev",
|
|
"RELEASE_AWS_DB_NAME": "ray_ci",
|
|
"RELEASE_AWS_DB_TABLE": "release_test_result",
|
|
"AWS_REGION": "us-west-2",
|
|
},
|
|
"agents": {"queue": str(RELEASE_QUEUE_DEFAULT)},
|
|
"plugins": [
|
|
{
|
|
DOCKER_PLUGIN_KEY: {
|
|
"image": "python:3.10",
|
|
"shell": ["/bin/bash", "-elic"],
|
|
"propagate-environment": True,
|
|
"volumes": [
|
|
"/var/lib/buildkite/builds:/var/lib/buildkite/builds",
|
|
"/usr/local/bin/buildkite-agent:/usr/local/bin/buildkite-agent",
|
|
f"{DEFAULT_ARTIFACTS_DIR_HOST}:{DEFAULT_ARTIFACTS_DIR_HOST}",
|
|
],
|
|
"environment": ["BUILDKITE_BUILD_PATH=/var/lib/buildkite/builds"],
|
|
}
|
|
}
|
|
],
|
|
"artifact_paths": [f"{DEFAULT_ARTIFACTS_DIR_HOST}/**/*"],
|
|
"priority": 0,
|
|
"retry": {
|
|
"automatic": [
|
|
{
|
|
"exit_status": os.environ.get("BUILDKITE_RETRY_CODE", 79),
|
|
"limit": os.environ.get("BUILDKITE_MAX_RETRIES", 1),
|
|
}
|
|
]
|
|
},
|
|
}
|
|
|
|
|
|
def get_step_for_test_group(
|
|
grouped_tests: Dict[str, List[Tuple[Test, bool]]],
|
|
minimum_run_per_test: int = 1,
|
|
test_collection_file: List[str] = None,
|
|
env: Optional[Dict] = None,
|
|
priority: int = 0,
|
|
global_config: Optional[str] = None,
|
|
is_concurrency_limit: bool = True,
|
|
block_step_key: Optional[str] = None,
|
|
gpu_map: Optional[Dict[str, str]] = None,
|
|
):
|
|
steps = []
|
|
for group in sorted(grouped_tests):
|
|
tests = grouped_tests[group]
|
|
group_steps = []
|
|
for test, smoke_test in tests:
|
|
for run_id in range(max(test.get("repeated_run", 1), minimum_run_per_test)):
|
|
step = get_step(
|
|
test,
|
|
test_collection_file,
|
|
run_id=run_id,
|
|
# Always report performance data to databrick. Since the data is
|
|
# indexed by branch and commit hash, we can always filter data later
|
|
report=True,
|
|
smoke_test=smoke_test,
|
|
env=env,
|
|
priority_val=priority,
|
|
global_config=global_config,
|
|
block_step_key=block_step_key,
|
|
gpu_map=gpu_map,
|
|
)
|
|
|
|
if not is_concurrency_limit:
|
|
step.pop("concurrency", None)
|
|
step.pop("concurrency_group", None)
|
|
|
|
group_steps.append(step)
|
|
|
|
group_step = {"group": group, "steps": group_steps}
|
|
steps.append(group_step)
|
|
|
|
return steps
|
|
|
|
|
|
def get_step(
|
|
test: Test,
|
|
test_collection_file: List[str] = None,
|
|
run_id: int = 1,
|
|
report: bool = False,
|
|
smoke_test: bool = False,
|
|
env: Optional[Dict] = None,
|
|
priority_val: int = 0,
|
|
global_config: Optional[str] = None,
|
|
block_step_key: Optional[str] = None,
|
|
gpu_map: Optional[Dict[str, str]] = None,
|
|
):
|
|
env = env or {}
|
|
step = copy.deepcopy(_DEFAULT_STEP_TEMPLATE)
|
|
|
|
cmd = [
|
|
"./release/run_release_test.sh",
|
|
shlex.quote(test["name"]),
|
|
]
|
|
|
|
for file in test_collection_file or []:
|
|
cmd += ["--test-collection-file", shlex.quote(file)]
|
|
|
|
if global_config:
|
|
cmd += ["--global-config", shlex.quote(global_config)]
|
|
|
|
if report and not bool(int(os.environ.get("NO_REPORT_OVERRIDE", "0"))):
|
|
cmd += ["--report"]
|
|
|
|
if smoke_test:
|
|
cmd += ["--smoke-test"]
|
|
|
|
num_retries = test.get("run", {}).get("num_retries")
|
|
if num_retries:
|
|
step["retry"]["automatic"][0]["limit"] = num_retries
|
|
|
|
step["commands"] = [" ".join(cmd)]
|
|
|
|
env_to_use = test.get("env", DEFAULT_ENVIRONMENT)
|
|
env_dict = load_environment(env_to_use)
|
|
env_dict.update(env)
|
|
|
|
# Set the project id for the test, based on the follow priority:
|
|
# 1. Specified in the test, as "project_id" field.
|
|
# 2. Specified in the specific test environment, as RELEASE_DEFAULT_PROJECT env var
|
|
# 3. Specified in the global environment, as RELEASE_DEFAULT_PROJECT env var
|
|
default_project_id = env_dict.get("RELEASE_DEFAULT_PROJECT")
|
|
env_dict["ANYSCALE_PROJECT"] = get_test_project_id(test, default_project_id)
|
|
|
|
step["env"].update(env_dict)
|
|
|
|
commit = get_test_env_var("RAY_COMMIT")
|
|
branch = get_test_env_var("RAY_BRANCH")
|
|
label = commit[:7] if commit else branch
|
|
|
|
if smoke_test:
|
|
concurrency_test = as_smoke_test(test)
|
|
else:
|
|
concurrency_test = test
|
|
concurrency_group, concurrency_limit = get_concurrency_group(concurrency_test)
|
|
|
|
step["concurrency_group"] = concurrency_group
|
|
step["concurrency"] = concurrency_limit
|
|
|
|
step["priority"] = priority_val
|
|
|
|
# Set queue to QUEUE_CLIENT for client tests
|
|
# (otherwise keep default QUEUE_DEFAULT)
|
|
if test.get("run", {}).get("type") == "client":
|
|
step["agents"]["queue"] = str(RELEASE_QUEUE_CLIENT)
|
|
|
|
clone_test = copy.deepcopy(test) # avoid modifying the original test
|
|
clone_test.update_from_s3()
|
|
jailed = clone_test.get_state() == TestState.JAILED
|
|
full_label = ""
|
|
if jailed:
|
|
full_label += "[jailed]"
|
|
|
|
full_label += test["name"]
|
|
if smoke_test:
|
|
full_label += " [smoke test] "
|
|
full_label += f" ({label}) ({run_id})"
|
|
|
|
step["label"] = full_label
|
|
|
|
image = test.get_anyscale_byod_image()
|
|
base_image = test.get_anyscale_base_byod_image()
|
|
if test.require_custom_byod_image():
|
|
step["depends_on"] = generate_custom_build_step_key(image)
|
|
else:
|
|
step["depends_on"] = get_prerequisite_step(image, base_image, gpu_map)
|
|
|
|
if block_step_key:
|
|
if not step["depends_on"]:
|
|
step["depends_on"] = block_step_key
|
|
else:
|
|
step["depends_on"] = [step["depends_on"], block_step_key]
|
|
return step
|
|
|
|
|
|
def generate_block_step(num_tests: int):
|
|
step = {
|
|
"block": "Run release tests",
|
|
"depends_on": None,
|
|
"key": "block_run_release_tests",
|
|
"prompt": f"You are triggering {num_tests} tests. Do you want to proceed?",
|
|
}
|
|
return step
|