ray/release/ray_release/util.py
Kai Fricke 7091a32fe1
[ci/release] Support running tests on staging (#25889)
This adds "environments" to the release package that can be used to configure some environment variables. These variables will be loaded either by an `--env` argument or a `env` definition in the test definition and can be used to e.g. run release tests on staging.
2022-06-28 10:14:01 -07:00

150 lines
3.7 KiB
Python

import collections
import hashlib
import json
import os
import subprocess
import time
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
import requests
from ray_release.logger import logger
if TYPE_CHECKING:
from anyscale.sdk.anyscale_client.sdk import AnyscaleSDK
class DeferredEnvVar:
def __init__(self, var: str, default: Optional[str] = None):
self._var = var
self._default = default
def __str__(self):
return os.environ.get(self._var, self._default)
ANYSCALE_HOST = DeferredEnvVar("ANYSCALE_HOST", "https://console.anyscale.com")
def deep_update(d, u) -> Dict:
for k, v in u.items():
if isinstance(v, collections.abc.Mapping):
d[k] = deep_update(d.get(k, {}), v)
else:
d[k] = v
return d
def dict_hash(dt: Dict[Any, Any]) -> str:
json_str = json.dumps(dt, sort_keys=True, ensure_ascii=True)
sha = hashlib.sha256()
sha.update(json_str.encode())
return sha.hexdigest()
def url_exists(url: str) -> bool:
return requests.head(url, allow_redirects=True).status_code == 200
def resolve_url(url: str) -> str:
return requests.head(url, allow_redirects=True).url
def format_link(link: str) -> str:
# Use ANSI escape code to allow link to be clickable
# https://buildkite.com/docs/pipelines/links-and-images
# -in-log-output
if os.environ.get("BUILDKITE_COMMIT"):
return "\033]1339;url='" + link + "'\a\n"
# Else, no buildkite:
return link
def anyscale_project_url(project_id: str) -> str:
return (
f"{ANYSCALE_HOST}"
f"/o/anyscale-internal/projects/{project_id}"
f"/?tab=session-list"
)
def anyscale_cluster_url(project_id: str, session_id: str) -> str:
return (
f"{ANYSCALE_HOST}"
f"/o/anyscale-internal/projects/{project_id}"
f"/clusters/{session_id}"
)
def anyscale_cluster_compute_url(compute_tpl_id: str) -> str:
return (
f"{ANYSCALE_HOST}"
f"/o/anyscale-internal/configurations/cluster-computes"
f"/{compute_tpl_id}"
)
def anyscale_cluster_env_build_url(build_id: str) -> str:
return (
f"{ANYSCALE_HOST}"
f"/o/anyscale-internal/configurations/app-config-details"
f"/{build_id}"
)
_anyscale_sdk = None
def get_anyscale_sdk(use_cache: bool = True) -> "AnyscaleSDK":
from anyscale.sdk.anyscale_client.sdk import AnyscaleSDK
global _anyscale_sdk
if use_cache and _anyscale_sdk:
return _anyscale_sdk
_anyscale_sdk = AnyscaleSDK(host=str(ANYSCALE_HOST))
return _anyscale_sdk
def exponential_backoff_retry(
f, retry_exceptions, initial_retry_delay_s, max_retries
) -> None:
retry_cnt = 0
retry_delay_s = initial_retry_delay_s
while True:
try:
return f()
except retry_exceptions as e:
retry_cnt += 1
if retry_cnt > max_retries:
raise
logger.info(
f"Retry function call failed due to {e} "
f"in {retry_delay_s} seconds..."
)
time.sleep(retry_delay_s)
retry_delay_s *= 2
def run_bash_script(bash_script: str) -> None:
subprocess.run(f"bash {bash_script}", shell=True, check=True)
def reinstall_anyscale_dependencies() -> None:
logger.info("Re-installing `anyscale` package")
subprocess.check_output(
"pip install -U anyscale",
shell=True,
text=True,
)
def get_pip_packages() -> List[str]:
from pip._internal.operations import freeze
return list(freeze.freeze())
def python_version_str(python_version: Tuple[int, int]) -> str:
"""From (X, Y) to XY"""
return "".join([str(x) for x in python_version])