diff --git a/setup.py b/setup.py index 59ceb1a..e8f18b2 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ setuptools.setup( name="d2_docker", - version="0.0.1", + version="1.0.1", description="Dockers for DHIS2 instances", long_description=open("README.md", encoding="utf-8").read(), keywords=["python"], diff --git a/src/d2_docker/.empty/placeholder b/src/d2_docker/.empty/placeholder new file mode 100644 index 0000000..e69de29 diff --git a/src/d2_docker/config/dhis2-core-entrypoint.sh b/src/d2_docker/config/dhis2-core-entrypoint.sh index c77bbde..749eb64 100755 --- a/src/d2_docker/config/dhis2-core-entrypoint.sh +++ b/src/d2_docker/config/dhis2-core-entrypoint.sh @@ -38,8 +38,8 @@ if [ "$(id -u)" = "0" ]; then chown -R tomcat:tomcat $TOMCATDIR/temp \ $TOMCATDIR/work \ $TOMCATDIR/logs - chown -R tomcat:tomcat $DHIS2HOME + chmod +x "$0" || true exec su-exec tomcat "$0" "$@" fi fi diff --git a/src/d2_docker/config/dhis2-core-start.sh b/src/d2_docker/config/dhis2-core-start.sh index f58fc5f..0d599c8 100755 --- a/src/d2_docker/config/dhis2-core-start.sh +++ b/src/d2_docker/config/dhis2-core-start.sh @@ -17,10 +17,10 @@ dhis2_url="http://localhost:8080" psql_cmd="psql -v ON_ERROR_STOP=0 --quiet -h db -U dhis dhis2" pgrestore_cmd="pg_restore -h db -U dhis -d dhis2" configdir="/config" -scripts_dir="/config/scripts" -root_db_path="/config/data/db" -post_db_path="/config/data/db/post" -source_apps_path="/config/data/apps" +scripts_dir="/data/scripts" +root_db_path="/data/db" +post_db_path="/data/db/post" +source_apps_path="/data/apps" dest_apps_path="/DHIS2_home/files/" warfile="/usr/local/tomcat/webapps/ROOT.war" tomcatdir="/usr/local/tomcat" @@ -72,7 +72,7 @@ setup_tomcat() { wait_for_postgres() { debug "Waiting for postgres: ${host}:${psql_port}" - while ! nc -z $host $psql_port; do + while ! echo "select 1;" | $psql_cmd; do sleep 1 done } diff --git a/src/d2_docker/docker-compose.yml b/src/d2_docker/docker-compose.yml index 8f7ea2e..c90a685 100644 --- a/src/d2_docker/docker-compose.yml +++ b/src/d2_docker/docker-compose.yml @@ -6,10 +6,10 @@ services: - "com.eyeseetea.image-name=${DHIS2_DATA_IMAGE}" volumes: - home:/DHIS2_home - - data:/config/data - ./config:/config - - "${SCRIPTS_DIR}:/config/scripts" - - "${POST_SQL_DIR}:/config/data/db/post" + - data:/data + - "${SCRIPTS_DIR}:/data/scripts" + - "${POST_SQL_DIR}:/data/db/post" environment: CATALINA_OPTS: "-Dcontext.path=" JAVA_OPTS: "-Xmx7500m -Xms4000m" diff --git a/src/d2_docker/utils.py b/src/d2_docker/utils.py index 5aa7841..8376e55 100644 --- a/src/d2_docker/utils.py +++ b/src/d2_docker/utils.py @@ -10,6 +10,7 @@ PROJECT_NAME_PREFIX = "d2-docker" DHIS2_DATA_IMAGE = "dhis2-data" IMAGE_NAME_LABEL = "com.eyeseetea.image-name" +DOCKER_COMPOSE_SERVICES = ["gateway", "core", "db"] def get_logger(): @@ -72,12 +73,12 @@ def get_running_image_name(): "ps", "--filter", "label=" + IMAGE_NAME_LABEL, - '--format={{.Label "com.eyeseetea.image-name"}}', + '--format={{.Label "%s"}}' % IMAGE_NAME_LABEL, ], capture_output=True, ) output_lines = result.stdout.decode("utf-8").splitlines() - image_names = set(output_lines) + image_names = set(line for line in output_lines if line.strip()) if len(image_names) == 0: raise D2DockerError("There are no d2-docker images running") @@ -121,23 +122,30 @@ def get_image_status(image_name, first_port=8080): """ final_image_name = image_name or get_running_image_name() project_name = get_project_name(final_image_name) - output_lines = run_docker_ps(["--format={{.Names}} {{.Ports}}"]) + output_lines = run_docker_ps( + [ + "--filter", + "label=" + IMAGE_NAME_LABEL, + '--format={{.Label "%s"}} {{.Names}} {{.Ports}}' % IMAGE_NAME_LABEL, + ] + ) containers = {} port = None for line in output_lines: - parts = line.split(None, 1) - if len(parts) != 2: + parts = line.split(None, 2) + if len(parts) != 3: continue - container_name, ports = parts - if container_name.startswith(project_name + "_"): - service = container_name[len(project_name) + 1 :].split("_", 1)[0] + image_name_part, container_name, ports = parts + indexed_service = container_name.split("_")[-2:] + if image_name_part == final_image_name and indexed_service: + service = indexed_service[0] containers[service] = container_name if service == "gateway": port = get_port_from_docker_ports(ports) - if containers: + if containers and set(containers.keys()) == set(DOCKER_COMPOSE_SERVICES) and port: return {"state": "running", "containers": containers, "port": port} else: return {"state": "stopped"} @@ -219,10 +227,11 @@ def run_docker_compose( return run(["docker-compose", "-f", yaml_path, "-p", project_name, *args], env=env, **kwargs) -def get_absdir_for_docker_volume(directory, default="empty"): +def get_absdir_for_docker_volume(directory): """Return absolute path for given directory, with default fallback.""" if not directory: - return default + empty_directory = os.path.join(os.path.dirname(__file__), ".empty") + return empty_directory elif not os.path.isdir(directory): raise D2DockerError("Should be a directory: {}".format(directory)) else: @@ -365,7 +374,7 @@ def add_core_image_arg(parser): def running_containers(image_name, *up_args, **run_docker_compose_kwargs): """Start docker-compose services for an image in a context manager and stop it afterwards.""" try: - run_docker_compose(["up", "--detach", *up_args], image_name, **run_docker_compose_kwargs) + run_docker_compose(["up", "-d", *up_args], image_name, **run_docker_compose_kwargs) status = get_image_status(image_name) if status["state"] != "running": raise D2DockerError("Could not run image: {}".format(image_name)) diff --git a/test/run-tests.sh b/test/run-tests.sh new file mode 100644 index 0000000..3985a9d --- /dev/null +++ b/test/run-tests.sh @@ -0,0 +1,50 @@ +#!/bin/bash -x -e -u -o pipefail + +wait_for_dhis2() { + echo "Wait for Dhis2 instance" + while ! curl -u admin:district -sS http://localhost:8080/api/me.json 2>/dev/null | jq 2>/dev/null; do + sleep 10; + done +} + +expect_equal() { local actual=$1 expected=$2 + if test "$actual" != "$expected"; then + echo "Error:" + echo " expected = $expected" + echo " actual = $actual" + return 1; + fi +} + +wget -c "https://releases.dhis2.org/2.30/dhis.war" +wget -c "https://github.com/dhis2/dhis2-demo-db/raw/master/sierra-leone/2.30/dhis2-db-sierra-leone.sql.gz" +mkdir -p apps/ sql/ +echo "select * from users;" > sql/get-users.sql +echo "update userinfo set firstname = 'John2' where uid = 'xE7jOejl9FI';" > sql/set-name.sql + +d2-docker create core tokland/dhis2-core:2.30 --war=dhis.war +d2-docker create data tokland/dhis2-data:2.30-sierra \ +--sql=dhis2-db-sierra-leone.sql.gz --apps-dir=apps/ +d2-docker list +d2-docker start -d tokland/dhis2-data:2.30-sierra +wait_for_dhis2 + +d2-docker list | grep "tokland/dhis2-data:2.30-sierra" | grep "RUNNING" +d2-docker logs tokland/dhis2-data:2.30-sierra +name=$(curl -sS -u admin:district 'http://localhost:8080/api/me' | jq -r '.displayName') +expect_equal "$name" "John Traore" +d2-docker run-sql -i tokland/dhis2-data:2.30-sierra get-users.sql +d2-docker commit tokland/dhis2-data:2.30-sierra +d2-docker export image.tgz + +d2-docker stop tokland/dhis2-data:2.30-sierra +d2-docker copy tokland/dhis2-data:2.30-sierra data-sierra tokland/dhis2-data:2.30-sierra2 +d2-docker import image.tgz +d2-docker start -d --run-sql=sql image.tgz +wait_for_dhis2 + +name=$(curl -sS -u admin:district 'http://localhost:8080/api/me' | jq -r '.displayName') +expect_equal "$name" "John2 Traore" +d2-docker stop tokland/dhis2-data:2.30-sierra + +echo "Tests passed!"