def test_wait_for_service(mocker): from derex.runner.docker_utils import wait_for_service container = mocker.MagicMock() container.exec_run.return_value = mocker.MagicMock(exit_code=0) client = mocker.patch("derex.runner.docker_utils.client") client.containers.get.return_value = container wait_for_service("mysql", 'mysql -psecret -e "SHOW DATABASES"', 1) client.containers.get.assert_called_with("mysql") container.exec_run.assert_called_with('mysql -psecret -e "SHOW DATABASES"')
def test_wait_for_service(mocker): from derex.runner.docker_utils import wait_for_service # Test that a RuntimeError is raised if the container doesn't # exists with pytest.raises(RuntimeError): wait_for_service("service", 1) container_info = { "State": { "Status": "running", "Health": { "Status": "healthy" } } } api_client = mocker.patch("derex.runner.docker_utils.api_client") api_client.inspect_container.return_value = container_info # Test that the result is successfull when the container # is running or restarting and healthy result = wait_for_service("service", 1) api_client.inspect_container.assert_called_with("service") assert result == 0 container_info["State"]["Status"] = "restarting" result = wait_for_service("service", 1) assert result == 0 # Test that a RuntimeError is raised if the container status is # exited container_info["State"]["Status"] = "exited" with pytest.raises(RuntimeError): wait_for_service("service", 1) # Test that a TimeoutError is raised if the container status is # unhealthy container_info["State"]["Status"] = "running" container_info["State"]["Health"]["Status"] = "unhealthy" with pytest.raises(TimeoutError): wait_for_service("service", 1) # Test that a NotImplementedError is raised if the container doesn't # define an healtcheck container_info["State"]["Health"] = None with pytest.raises(NotImplementedError): wait_for_service("service", 1)
def e2e(project): """Run project e2e tests""" if not project.e2e_dir: click.echo(red(f"No e2e tests directory found in {project.root}"), err=True) return 1 try: wait_for_service("httpserver") except (TimeoutError, RuntimeError, NotImplementedError) as exc: click.echo(click.style(str(exc), fg="red")) sys.exit(1) click.echo(f"Running e2e Cypress tests from {project.e2e_dir}") test_compose_path = generate_ddc_test_compose(project) run_docker_compose( ["-f", str(test_compose_path), "run", "--rm", "cypress"], dry_run=False, exit_afterwards=True, )
def minio_update_key(old_key: str): """Run minio to re-key data with the new secret""" from derex.runner.ddc import run_ddc_services from derex.runner.docker_utils import wait_for_service from derex.runner.utils import derex_path wait_for_service("minio") MINIO_SCRIPT_PATH = derex_path( "derex/runner/compose_files/minio-update-key.sh") click.echo("Updating MinIO secret key...") compose_args = [ "run", "--rm", "-v", f"{MINIO_SCRIPT_PATH}:/minio-update-key.sh", "-e", f"MINIO_SECRET_KEY_OLD={old_key}", "--entrypoint", "/bin/sh", "-T", "minio", "/minio-update-key.sh", ] try: run_ddc_services(compose_args) except RuntimeError: return 1 # We need to recreate the minio container since we can't set # the new key in the running one # https://github.com/moby/moby/issues/8838 # We'll let `docker-compose up` recreate it for us, if needed click.echo("\nRecreating MinIO container...") compose_args = ["up", "-d", "minio"] run_ddc_services(compose_args) wait_for_service("minio") click.echo("\nMinIO secret key updated successfully!") return 0
def create_index(project): """Prime the elasticsearch index for the Forum service""" from derex.runner.ddc import run_ddc_project from derex.runner.docker_utils import wait_for_service try: wait_for_service("elasticsearch") except (TimeoutError, RuntimeError, NotImplementedError) as exc: click.echo(click.style(str(exc), fg="red")) sys.exit(1) compose_args = [ "run", "--rm", "-T", "forum", "sh", "-c", """bundle exec rake search:initialize && bundle exec rake search:rebuild_index """, ] run_ddc_project(compose_args, project=project) return 0
def ddc_project(): """Proxy for docker-compose: writes a docker-compose.yml file with the configuration of this project, and then run `docker-compose` on it. You probably want do run `ddc-project up -d` and `ddc-project logs -f`. """ check_docker() setup_logging() try: project = Project() except ValueError as exc: click.echo(str(exc)) sys.exit(1) compose_args, dry_run = ddc_parse_args(sys.argv) # If trying to start up containers, first check that needed services are running is_start_cmd = any(param in compose_args for param in ["up", "start"]) if is_start_cmd: for service in ["mysql", "mongodb", "rabbitmq"]: try: wait_for_service(service) except (TimeoutError, RuntimeError, NotImplementedError) as exc: click.echo(click.style(str(exc), fg="red")) sys.exit(1) run_ddc_project(list(compose_args), project, dry_run=dry_run, exit_afterwards=True)
def inner(*args, **kwargs): wait_for_service("mysql") return func(*args, **kwargs)
def wait_for_mysql(max_seconds: int = 20): """With a freshly created container mysql might need a bit of time to prime its files. This functions waits up to max_seconds seconds. """ return wait_for_service("mysql", 'mysql -psecret -e "SHOW DATABASES"', max_seconds)
from derex.runner.secrets import DerexSecrets from derex.runner.secrets import get_secret from functools import wraps from pymongo import MongoClient from typing import cast from typing import List from typing import Optional import logging import urllib.parse logger = logging.getLogger(__name__) MONGODB_ROOT_PASSWORD = get_secret(DerexSecrets.mongodb) try: wait_for_service("mongodb") container = docker_client.containers.get("mongodb") mongo_address = container.attrs["NetworkSettings"]["Networks"]["derex"][ "IPAddress"] user = urllib.parse.quote_plus(MONGODB_ROOT_USER) password = urllib.parse.quote_plus(MONGODB_ROOT_PASSWORD) MONGODB_CLIENT = MongoClient( f"mongodb://{user}:{password}@{mongo_address}:27017/", authSource="admin") except RuntimeError as e: MONGODB_CLIENT = None logger.warning(e) def ensure_mongodb(func): """Decorator to raise an exception before running a function in case the mongodb
def wait_for_mongodb(max_seconds: int = 20): """With a freshly created container mongodb might need a bit of time to prime its files. This functions waits up to max_seconds seconds. """ return wait_for_service("mongodb", "mongo", max_seconds)