Source code for ephemeris.sleep

#!/usr/bin/env python
"""Utility to do a blocking sleep until a Galaxy instance is responsive.
This is useful in docker images, in RUN steps, where one needs to wait
for a currently starting Galaxy to be alive, before API requests can be
made successfully.
The script functions by making repeated requests to
``http(s)://fqdn/api/version``, an API which requires no authentication
to access."""

import sys
import time
from argparse import ArgumentParser

import requests
from galaxy.util import unicodify

from .common_parser import (
    get_common_args,
    HideUnderscoresHelpFormatter,
)

DEFAULT_SLEEP_WAIT = 1
MESSAGE_KEY_NOT_YET_VALID = "[%02d] Provided key not (yet) valid... %s\n"
MESSAGE_INVALID_JSON = "[%02d] No valid json returned... %s\n"
MESSAGE_FETCHING_USER = "[%02d] Connection error fetching user details, exiting with error code. %s\n"
MESSAGE_KEY_NOT_YET_ADMIN = "[%02d] Provided key not (yet) admin... %s\n"
MESSAGE_GALAXY_NOT_YET_UP = "[%02d] Galaxy not up yet... %s\n"
MESSAGE_TIMEOUT = "Failed to contact Galaxy within timeout (%s), exiting with error code.\n"


def _parser():
    """Constructs the parser object"""
    parent = get_common_args(login_required=False)
    parser = ArgumentParser(
        parents=[parent],
        usage="usage: %(prog)s <options>",
        formatter_class=HideUnderscoresHelpFormatter,
        description="Script to sleep and wait for Galaxy to be alive.",
    )
    parser.add_argument(
        "--timeout",
        default=0,
        type=int,
        help="Galaxy startup timeout in seconds. The default value of 0 waits forever",
    )
    parser.add_argument(
        "-a",
        "--api-key",
        "--api_key",
        dest="api_key",
        help="Sleep until key becomes available.",
    )
    parser.add_argument("--ensure-admin", "--ensure_admin", default=False, action="store_true")
    return parser


[docs] class SleepCondition: def __init__(self): self.sleep = True
[docs] def cancel(self): self.sleep = False
[docs] def galaxy_wait( galaxy_url, verbose=False, timeout=0, sleep_condition=None, api_key=None, ensure_admin=False, ): """Pass user_key to ensure it works before returning.""" if verbose: sys.stdout.write(f"calling galaxy_wait with timeout={timeout} ensure_admin={ensure_admin}\n\n\n") sys.stdout.flush() version_url = galaxy_url + "/api/version" if api_key: # adding the key to the URL will ensure Galaxy returns invalid responses until # the key is available. version_url = f"{version_url}?key={api_key}" current_user_url = f"{galaxy_url}/api/users/current?key={api_key}" else: assert not ensure_admin if sleep_condition is None: sleep_condition = SleepCondition() count = 0 version_obtained = False while sleep_condition.sleep: try: if not version_obtained: result = requests.get(version_url) if result.status_code == 403: if verbose: sys.stdout.write(MESSAGE_KEY_NOT_YET_VALID % (count, result.__str__())) sys.stdout.flush() else: try: result = result.json() if verbose: sys.stdout.write("Galaxy Version: %s\n" % result["version_major"]) sys.stdout.flush() version_obtained = True except ValueError: if verbose: sys.stdout.write(MESSAGE_INVALID_JSON % (count, result.__str__())) sys.stdout.flush() if version_obtained: if ensure_admin: result = requests.get(current_user_url) if result.status_code != 200: if verbose: sys.stdout.write(MESSAGE_FETCHING_USER % (count, result.__str__())) sys.stdout.flush() return False result = result.json() is_admin = result["is_admin"] if is_admin: if verbose: sys.stdout.write("Verified supplied key an admin key.\n") sys.stdout.flush() break else: if verbose: sys.stdout.write(MESSAGE_KEY_NOT_YET_ADMIN % (count, result.__str__())) sys.stdout.flush() else: break except requests.exceptions.ConnectionError as e: if verbose: sys.stdout.write(MESSAGE_GALAXY_NOT_YET_UP % (count, unicodify(e)[:100])) sys.stdout.flush() count += 1 # If we cannot talk to galaxy and are over the timeout if timeout != 0 and count > timeout: sys.stderr.write(MESSAGE_TIMEOUT % timeout) return False time.sleep(DEFAULT_SLEEP_WAIT) return True
[docs] def main(argv=None): """ Main function """ options = _parser().parse_args(argv) galaxy_alive = galaxy_wait( galaxy_url=options.galaxy, verbose=options.verbose, timeout=options.timeout, api_key=options.api_key, ensure_admin=options.ensure_admin, ) exit_code = 0 if galaxy_alive else 1 sys.exit(exit_code)
if __name__ == "__main__": main()