From bbe52860a54695977c80f4231c8ff740222a9805 Mon Sep 17 00:00:00 2001 From: cgbautista Date: Thu, 10 Jul 2025 13:55:22 +0200 Subject: [PATCH 01/11] Added a feature to enable an open-source APM: glowroot to the tomcat service. It downloads the latest version (--glowroot) or you can specify an specific zip file that you already have downloaded (--glowroot-zip), by default it will listen on port 4000, but you can change it with --glowroot-port (only if glowroot is enabled by any of the other two ways). Latest version is prioritized over an specific file --- README.md | 9 +++- setup.py | 2 +- src/d2_docker/commands/start.py | 6 +++ src/d2_docker/config/dhis2-core-entrypoint.sh | 15 +++++++ src/d2_docker/docker-compose.yml | 2 + src/d2_docker/utils.py | 45 +++++++++++++++++-- 6 files changed, 73 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0b1c2b8..33f4e04 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ - Operating System: GNU/Linux or Windows 10. - Python >= 3.5 (with setuptools) -- Docker >= 18 -- Docker compose >= 1.17 +- Docker >= 20.10.13 +- Docker compose >= 2.0 - RAM memory: At least 4Gb for instance, preferrably 8Gb. On Ubuntu 22.04: @@ -69,6 +69,8 @@ Create a dhis2-data image from a .sql.gz SQL file and the apps and documents (or $ d2-docker create data docker.eyeseetea.com/eyeseetea/dhis2-data:2.37.9-sierra --sql=sierra-db.sql.gz [--apps-dir=path/to/apps] [--documents-dir=path/to/document] [--datavalues-dir=path/to/dataValue] ``` +There are demo database files at [databases.dhis2.org](https://databases.dhis2.org/) that may be used for testing purposses. The database downloaded should correspond to the core version created; if there is no database file for the created core version, a prior version of the database should work. + ### Start a DHIS2 instance Start a new container from a _dhis2-data_ base image: @@ -92,6 +94,9 @@ Some notes: - Use option `--java-opts="JAVA_OPTS"` to override the default JAVA_OPTS for the Tomcat process. That's tipically used to set the maximum/initial Heap Memory size (for example: `--java-opts="-Xmx3500m -Xms2500m"`) - Use option `--postgis-version=13-3.1-alpine` to specify the PostGIS version to use. By default, 10-2.5-alpine is used. - Use option `--debug-port=PORT` to specify the debug port of the Tomcat process. +- Use option `--glowroot-port=PORT` to specify the APM glowroot port of the Tomcat process. +- Use option `--glowroot` to use the latest version of glowroot in the Tomcat process. +- Use option `--glowroot-zip=FILE` to specify the zip file with a version of glowroot to run in the Tomcat process. #### Custom DHIS2 dhis.conf diff --git a/setup.py b/setup.py index 86d1293..423e8ad 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ setuptools.setup( name="d2_docker", - version="1.15.0.b2", + version="1.16.0", description="Dockers for DHIS2 instances", long_description=open("README.md", encoding="utf-8").read(), keywords=["python"], diff --git a/src/d2_docker/commands/start.py b/src/d2_docker/commands/start.py index 2ff59f4..bd6384c 100644 --- a/src/d2_docker/commands/start.py +++ b/src/d2_docker/commands/start.py @@ -41,6 +41,9 @@ def setup(parser): parser.add_argument("--postgis-version", type=str, help="Set PostGIS database version") parser.add_argument("--enable-postgres-queries-logging", action="store_true", help="Enable Postgres queries logging") + parser.add_argument("--glowroot", action="store_true", help="Enables glowroot in tomcat in latest version") + parser.add_argument("--glowroot-zip", metavar="FILE", help="ZIP file with glowroot binaries") + parser.add_argument("--glowroot-port", metavar="PORT", help="Set glowroot port") def run(args): @@ -113,6 +116,9 @@ def start(args): java_opts=args.java_opts, postgis_version=args.postgis_version, enable_postgres_queries_logging=args.enable_postgres_queries_logging, + glowroot=args.glowroot, + glowroot_zip=args.glowroot_zip, + glowroot_port=args.glowroot_port, ) if args.detach: diff --git a/src/d2_docker/config/dhis2-core-entrypoint.sh b/src/d2_docker/config/dhis2-core-entrypoint.sh index 65610e4..d1756a7 100755 --- a/src/d2_docker/config/dhis2-core-entrypoint.sh +++ b/src/d2_docker/config/dhis2-core-entrypoint.sh @@ -12,6 +12,9 @@ WARFILE=/usr/local/tomcat/webapps/ROOT.war TOMCATDIR=/usr/local/tomcat DHIS2HOME=/DHIS2_home DATA_DIR=/data +GLOWROOT_ZIP="/opt/glowroot.zip" +GLOWROOT_DIR="/opt/glowroot" + debug() { echo "[dhis2-core-entrypoint] $*" >&2 @@ -49,6 +52,18 @@ if [ "$(id -u)" = "0" ]; then rm -v $WARFILE # just to save space fi + if [ -f $GLOWROOT_ZIP ] && [ ! -d $GLOWROOT_DIR ] ; then + unzip -q $GLOWROOT_ZIP -d /opt/ || [ $? -le 1 ] + if [ -d $GLOWROOT_DIR ] ; then + echo '{ "web": { "bindAddress": "0.0.0.0", "port": "4000" }}' > $GLOWROOT_DIR/admin.json + chown -R tomcat:tomcat $GLOWROOT_DIR + chmod -R u=rwX,g=rX,o-rwx $GLOWROOT_DIR + echo 'export CATALINA_OPTS="$CATALINA_OPTS -javaagent:/opt/glowroot/glowroot.jar"' > /usr/local/tomcat/bin/setenv.sh + chmod ugo+x /usr/local/tomcat/bin/setenv.sh + chown tomcat:tomcat /usr/local/tomcat/bin/setenv.sh + fi + fi + wait_for_data_container_to_finish_copy mkdir -p $DATA_DIR/apps diff --git a/src/d2_docker/docker-compose.yml b/src/d2_docker/docker-compose.yml index bf6d447..36a1ed7 100644 --- a/src/d2_docker/docker-compose.yml +++ b/src/d2_docker/docker-compose.yml @@ -5,6 +5,7 @@ services: - "com.eyeseetea.image-name=${DHIS2_DATA_IMAGE}" volumes: - home:/DHIS2_home + - ${GLOWROOT_ZIP}:/opt/glowroot.zip - ${DHIS_CONF}:/config/override/dhis2/dhis.conf - ${ROOT_PATH}/config:/config - data:/data @@ -27,6 +28,7 @@ services: - "data" ports: - "${DHIS2_CORE_DEBUG_PORT}" + - "${GLOWROOT_PORT}" db: image: "postgis/postgis:${POSTGIS_VERSION:-14-3.2-alpine}" shm_size: 1gb diff --git a/src/d2_docker/utils.py b/src/d2_docker/utils.py index c92cec4..f95a3b2 100644 --- a/src/d2_docker/utils.py +++ b/src/d2_docker/utils.py @@ -10,6 +10,8 @@ import time import yaml import urllib.request +import json +import zipfile from setuptools._distutils import dir_util from pathlib import Path from typing import Optional @@ -39,6 +41,16 @@ def get_dhis2_war_url(version): ) return releases_base_url + "/" + path +def get_latest_glowroot_url(): + glowroot_releases_url = "https://api.github.com/repos/glowroot/glowroot/releases/latest" + glowroot_download_url = "https://github.com/glowroot/glowroot/releases/download" + with urllib.request.urlopen(glowroot_releases_url) as response: + data = response.read().decode() + release_info = json.loads(data) + + tag_name = release_info["tag_name"] + return "{}/{}/glowroot-{}-dist.zip".format(glowroot_download_url, tag_name, tag_name.lstrip("v")) + def docker_build(directory, tag): return run(["docker", "build", "--platform", "linux/amd64", "--tag", tag, directory]) @@ -261,6 +273,9 @@ def run_docker_compose( tomcat_server=None, postgis_version=None, enable_postgres_queries_logging=False, + glowroot=None, + glowroot_zip=None, + glowroot_port=None, **kwargs, ): """ @@ -270,11 +285,30 @@ def run_docker_compose( The DHIS2_CORE_IMAGE is inferred from the data repo, if not specified. """ + final_image_name = data_image or get_running_image_name() project_name = get_project_name(final_image_name) core_image_name = core_image or get_core_image_name(data_image) post_sql_dir_abs = get_absdir_for_docker_volume(post_sql_dir) scripts_dir_abs = get_absdir_for_docker_volume(scripts_dir) + glowroot_path=None + + if args[0] == "up": + glowroot_file = tempfile.NamedTemporaryFile(delete=False, prefix="glowroot_", suffix=".zip", dir="/tmp") + glowroot_path = glowroot_file.name + + atexit.register(lambda: os.remove(glowroot_path) if os.path.exists(glowroot_path) else None) + if glowroot_zip: + logger.debug("Copy zip file: {} -> {}".format(glowroot_zip, glowroot_path)) + shutil.copy(glowroot_zip, glowroot_path) + elif glowroot: + glowroot_url = get_latest_glowroot_url() + logger.info("Download file: {}".format(glowroot_url)) + urllib.request.urlretrieve(glowroot_url, glowroot_path) + else: + # empty zipfile + with zipfile.ZipFile(glowroot_path, mode="w") as zf: + pass env_pairs = [ ("DHIS2_DATA_IMAGE", final_image_name), @@ -296,13 +330,18 @@ def run_docker_compose( # Add ROOT_PATH from environment (required when run inside a docker) ("ROOT_PATH", ROOT_PATH), ("PSQL_ENABLE_QUERY_LOGS", "") if not enable_postgres_queries_logging else None, + ("GLOWROOT_PORT", "{}:4000".format(glowroot_port) if glowroot_port else "4000:4000") if (glowroot or glowroot_zip) else ("GLOWROOT_PORT", None), + ("GLOWROOT_ZIP", get_absfile_for_docker_volume(glowroot_path)), ] env = dict((k, v) for (k, v) in [pair for pair in env_pairs if pair] if v is not None) def process_yaml(data): - if "DHIS2_CORE_DEBUG_PORT" not in env: - core = data["services"]["core"] - core["ports"] = [port for port in core["ports"] if "DHIS2_CORE_DEBUG_PORT" not in port] + # Removes ports for "core" service in docker-compose if the environmental variables are not established + core = data["services"]["core"] + env_ports = ["DHIS2_CORE_DEBUG_PORT", "GLOWROOT_PORT"] + for env_port in env_ports: + if env_port not in env: + core["ports"] = [port for port in core["ports"] if env_port not in port] return data From 7011a1f44173afff7eabd256430ba262f333d6a2 Mon Sep 17 00:00:00 2001 From: cgbautista Date: Tue, 29 Jul 2025 15:32:27 +0200 Subject: [PATCH 02/11] Code cleanup --- README.md | 17 +++++-- src/d2_docker/commands/start.py | 1 + src/d2_docker/config/dhis2-core-entrypoint.sh | 22 ++++++--- src/d2_docker/glowroot.py | 46 +++++++++++++++++++ src/d2_docker/utils.py | 35 ++------------ 5 files changed, 79 insertions(+), 42 deletions(-) create mode 100644 src/d2_docker/glowroot.py diff --git a/README.md b/README.md index 33f4e04..08db6a6 100644 --- a/README.md +++ b/README.md @@ -94,9 +94,6 @@ Some notes: - Use option `--java-opts="JAVA_OPTS"` to override the default JAVA_OPTS for the Tomcat process. That's tipically used to set the maximum/initial Heap Memory size (for example: `--java-opts="-Xmx3500m -Xms2500m"`) - Use option `--postgis-version=13-3.1-alpine` to specify the PostGIS version to use. By default, 10-2.5-alpine is used. - Use option `--debug-port=PORT` to specify the debug port of the Tomcat process. -- Use option `--glowroot-port=PORT` to specify the APM glowroot port of the Tomcat process. -- Use option `--glowroot` to use the latest version of glowroot in the Tomcat process. -- Use option `--glowroot-zip=FILE` to specify the zip file with a version of glowroot to run in the Tomcat process. #### Custom DHIS2 dhis.conf @@ -381,3 +378,17 @@ $ cp flaskenv.secret ~/.config/d2-docker/ $ curl -sS 'http://localhost:5000/harbor/https://docker.eyeseetea.com/api/v2.0/quotas/1' | jq ``` + +## Glowroot + +Glowroot is an open-source Java APM (Application Performance Monitoring) tool. It can help detect and diagnose application performance problems, tracing slow requests, errors, response time breakdowns, SQL capture and more. +When starting a container, there are a few options to enable glowroot on the Tomcat process: +- Use option `--glowroot-port=PORT` to specify the APM glowroot port of the Tomcat process. +- Use option `--glowroot` to use the latest version of glowroot in the Tomcat process. +- Use option `--glowroot-zip=FILE` to specify the zip file with a version of glowroot to run in the Tomcat process. + +### Run d2-docker with glowroot enabled in the default port at the latest version available + +``` +$ d2-docker start docker.eyeseetea.com/eyeseetea/dhis2-data:2.37.9-sierra --glowroot +``` \ No newline at end of file diff --git a/src/d2_docker/commands/start.py b/src/d2_docker/commands/start.py index bd6384c..c59a5b8 100644 --- a/src/d2_docker/commands/start.py +++ b/src/d2_docker/commands/start.py @@ -41,6 +41,7 @@ def setup(parser): parser.add_argument("--postgis-version", type=str, help="Set PostGIS database version") parser.add_argument("--enable-postgres-queries-logging", action="store_true", help="Enable Postgres queries logging") + parser.add_argument("--glowroot", action="store_true", help="Enables glowroot in tomcat in latest version") parser.add_argument("--glowroot-zip", metavar="FILE", help="ZIP file with glowroot binaries") parser.add_argument("--glowroot-port", metavar="PORT", help="Set glowroot port") diff --git a/src/d2_docker/config/dhis2-core-entrypoint.sh b/src/d2_docker/config/dhis2-core-entrypoint.sh index d1756a7..6e01881 100755 --- a/src/d2_docker/config/dhis2-core-entrypoint.sh +++ b/src/d2_docker/config/dhis2-core-entrypoint.sh @@ -46,14 +46,14 @@ wait_for_data_container_to_finish_copy() { } -if [ "$(id -u)" = "0" ]; then - if [ -f $WARFILE ]; then - unzip -q $WARFILE -d $TOMCATDIR/webapps/ROOT - rm -v $WARFILE # just to save space - fi - +setup_glowroot() { if [ -f $GLOWROOT_ZIP ] && [ ! -d $GLOWROOT_DIR ] ; then - unzip -q $GLOWROOT_ZIP -d /opt/ || [ $? -le 1 ] + status=0 + unzip -q "$GLOWROOT_ZIP" -d /opt/ || status=$? + # Ignore RC=1 that implies only warnings and no errors (like an empty zip file) + if [ $status -gt 1 ]; then + exit $status + fi if [ -d $GLOWROOT_DIR ] ; then echo '{ "web": { "bindAddress": "0.0.0.0", "port": "4000" }}' > $GLOWROOT_DIR/admin.json chown -R tomcat:tomcat $GLOWROOT_DIR @@ -63,7 +63,15 @@ if [ "$(id -u)" = "0" ]; then chown tomcat:tomcat /usr/local/tomcat/bin/setenv.sh fi fi +} + +if [ "$(id -u)" = "0" ]; then + if [ -f $WARFILE ]; then + unzip -q $WARFILE -d $TOMCATDIR/webapps/ROOT + rm -v $WARFILE # just to save space + fi + setup_glowroot wait_for_data_container_to_finish_copy mkdir -p $DATA_DIR/apps diff --git a/src/d2_docker/glowroot.py b/src/d2_docker/glowroot.py new file mode 100644 index 0000000..2b6cda2 --- /dev/null +++ b/src/d2_docker/glowroot.py @@ -0,0 +1,46 @@ +import atexit +import json +import os +import shutil +import tempfile +import urllib.request +import zipfile +from d2_docker import utils + +GLOWROOT_DEFAULT_PORT = "4000" + +def get_latest_glowroot_url(): + glowroot_releases_url = "https://api.github.com/repos/glowroot/glowroot/releases/latest" + glowroot_download_url = "https://github.com/glowroot/glowroot/releases/download" + with urllib.request.urlopen(glowroot_releases_url) as response: + data = response.read().decode() + release_info = json.loads(data) + + tag_name = release_info["tag_name"] + return "{}/{}/glowroot-{}-dist.zip".format(glowroot_download_url, tag_name, tag_name.lstrip("v")) + +def get_glowroot_zip(command, glowroot_zip, glowroot): + logger = utils.logger + glowroot_path=None + if command == "up": + glowroot_file = tempfile.NamedTemporaryFile(delete=False, prefix="glowroot_", suffix=".zip", dir="/tmp") + glowroot_path = glowroot_file.name + + atexit.register(lambda: os.remove(glowroot_path) if os.path.exists(glowroot_path) else None) + if glowroot_zip: + logger.debug("Copy zip file: {} -> {}".format(glowroot_zip, glowroot_path)) + shutil.copy(glowroot_zip, glowroot_path) + elif glowroot: + glowroot_url = get_latest_glowroot_url() + logger.info("Download file: {}".format(glowroot_url)) + urllib.request.urlretrieve(glowroot_url, glowroot_path) + else: + # empty zipfile + with zipfile.ZipFile(glowroot_path, mode="w") as zf: + pass + + return utils.get_absfile_for_docker_volume(glowroot_path) + +def get_port_glowroot(glowroot_port, glowroot_zip, glowroot): + port = glowroot_port if glowroot_port else GLOWROOT_DEFAULT_PORT + return "{}:{}".format(port, GLOWROOT_DEFAULT_PORT) if (glowroot_port or glowroot_zip or glowroot) else None diff --git a/src/d2_docker/utils.py b/src/d2_docker/utils.py index f95a3b2..0442a6c 100644 --- a/src/d2_docker/utils.py +++ b/src/d2_docker/utils.py @@ -10,13 +10,12 @@ import time import yaml import urllib.request -import json -import zipfile from setuptools._distutils import dir_util from pathlib import Path from typing import Optional import d2_docker +from d2_docker.glowroot import get_glowroot_zip, get_port_glowroot from .image_name import ImageName PROJECT_NAME_PREFIX = "d2-docker" @@ -41,16 +40,6 @@ def get_dhis2_war_url(version): ) return releases_base_url + "/" + path -def get_latest_glowroot_url(): - glowroot_releases_url = "https://api.github.com/repos/glowroot/glowroot/releases/latest" - glowroot_download_url = "https://github.com/glowroot/glowroot/releases/download" - with urllib.request.urlopen(glowroot_releases_url) as response: - data = response.read().decode() - release_info = json.loads(data) - - tag_name = release_info["tag_name"] - return "{}/{}/glowroot-{}-dist.zip".format(glowroot_download_url, tag_name, tag_name.lstrip("v")) - def docker_build(directory, tag): return run(["docker", "build", "--platform", "linux/amd64", "--tag", tag, directory]) @@ -291,24 +280,6 @@ def run_docker_compose( core_image_name = core_image or get_core_image_name(data_image) post_sql_dir_abs = get_absdir_for_docker_volume(post_sql_dir) scripts_dir_abs = get_absdir_for_docker_volume(scripts_dir) - glowroot_path=None - - if args[0] == "up": - glowroot_file = tempfile.NamedTemporaryFile(delete=False, prefix="glowroot_", suffix=".zip", dir="/tmp") - glowroot_path = glowroot_file.name - - atexit.register(lambda: os.remove(glowroot_path) if os.path.exists(glowroot_path) else None) - if glowroot_zip: - logger.debug("Copy zip file: {} -> {}".format(glowroot_zip, glowroot_path)) - shutil.copy(glowroot_zip, glowroot_path) - elif glowroot: - glowroot_url = get_latest_glowroot_url() - logger.info("Download file: {}".format(glowroot_url)) - urllib.request.urlretrieve(glowroot_url, glowroot_path) - else: - # empty zipfile - with zipfile.ZipFile(glowroot_path, mode="w") as zf: - pass env_pairs = [ ("DHIS2_DATA_IMAGE", final_image_name), @@ -330,8 +301,8 @@ def run_docker_compose( # Add ROOT_PATH from environment (required when run inside a docker) ("ROOT_PATH", ROOT_PATH), ("PSQL_ENABLE_QUERY_LOGS", "") if not enable_postgres_queries_logging else None, - ("GLOWROOT_PORT", "{}:4000".format(glowroot_port) if glowroot_port else "4000:4000") if (glowroot or glowroot_zip) else ("GLOWROOT_PORT", None), - ("GLOWROOT_ZIP", get_absfile_for_docker_volume(glowroot_path)), + ("GLOWROOT_PORT", get_port_glowroot(glowroot_port, glowroot_zip, glowroot)), + ("GLOWROOT_ZIP", get_glowroot_zip(args[0], glowroot_zip, glowroot)), ] env = dict((k, v) for (k, v) in [pair for pair in env_pairs if pair] if v is not None) From e1ed7a8e3e3304d89bc7cae8b4bae5a7d64e5913 Mon Sep 17 00:00:00 2001 From: cgbautista Date: Tue, 26 Aug 2025 15:15:42 +0200 Subject: [PATCH 03/11] Avoid warning output from unzip --- src/d2_docker/config/dhis2-core-entrypoint.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/d2_docker/config/dhis2-core-entrypoint.sh b/src/d2_docker/config/dhis2-core-entrypoint.sh index 6e01881..4265882 100755 --- a/src/d2_docker/config/dhis2-core-entrypoint.sh +++ b/src/d2_docker/config/dhis2-core-entrypoint.sh @@ -49,9 +49,10 @@ wait_for_data_container_to_finish_copy() { setup_glowroot() { if [ -f $GLOWROOT_ZIP ] && [ ! -d $GLOWROOT_DIR ] ; then status=0 - unzip -q "$GLOWROOT_ZIP" -d /opt/ || status=$? + output=$(unzip -q "$GLOWROOT_ZIP" -d /opt/ 2>&1 || status=$?) # Ignore RC=1 that implies only warnings and no errors (like an empty zip file) if [ $status -gt 1 ]; then + echo "$output" exit $status fi if [ -d $GLOWROOT_DIR ] ; then From 344243a4c6e8009c644a425bcc1d0f9e4b6e9f4c Mon Sep 17 00:00:00 2001 From: cgbautista Date: Tue, 26 Aug 2025 15:59:36 +0200 Subject: [PATCH 04/11] status was always 0 because incorrect placement of parenthesis --- src/d2_docker/config/dhis2-core-entrypoint.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d2_docker/config/dhis2-core-entrypoint.sh b/src/d2_docker/config/dhis2-core-entrypoint.sh index 4265882..45b9a0a 100755 --- a/src/d2_docker/config/dhis2-core-entrypoint.sh +++ b/src/d2_docker/config/dhis2-core-entrypoint.sh @@ -49,7 +49,7 @@ wait_for_data_container_to_finish_copy() { setup_glowroot() { if [ -f $GLOWROOT_ZIP ] && [ ! -d $GLOWROOT_DIR ] ; then status=0 - output=$(unzip -q "$GLOWROOT_ZIP" -d /opt/ 2>&1 || status=$?) + output=$(unzip -q "$GLOWROOT_ZIP" -d /opt/ 2>&1) || status=$? # Ignore RC=1 that implies only warnings and no errors (like an empty zip file) if [ $status -gt 1 ]; then echo "$output" From 94a3dcec5ab34a13b28b11f6f541db31648b62c5 Mon Sep 17 00:00:00 2001 From: cgbautista Date: Thu, 2 Oct 2025 12:44:27 +0200 Subject: [PATCH 05/11] Fixed an error when `d2-docker logs` was used. --- src/d2_docker/glowroot.py | 2 +- src/d2_docker/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d2_docker/glowroot.py b/src/d2_docker/glowroot.py index 2b6cda2..34a99d7 100644 --- a/src/d2_docker/glowroot.py +++ b/src/d2_docker/glowroot.py @@ -22,7 +22,7 @@ def get_latest_glowroot_url(): def get_glowroot_zip(command, glowroot_zip, glowroot): logger = utils.logger glowroot_path=None - if command == "up": + if isinstance(command, list) and command[0] == "up": glowroot_file = tempfile.NamedTemporaryFile(delete=False, prefix="glowroot_", suffix=".zip", dir="/tmp") glowroot_path = glowroot_file.name diff --git a/src/d2_docker/utils.py b/src/d2_docker/utils.py index 0442a6c..bc2bf93 100644 --- a/src/d2_docker/utils.py +++ b/src/d2_docker/utils.py @@ -302,7 +302,7 @@ def run_docker_compose( ("ROOT_PATH", ROOT_PATH), ("PSQL_ENABLE_QUERY_LOGS", "") if not enable_postgres_queries_logging else None, ("GLOWROOT_PORT", get_port_glowroot(glowroot_port, glowroot_zip, glowroot)), - ("GLOWROOT_ZIP", get_glowroot_zip(args[0], glowroot_zip, glowroot)), + ("GLOWROOT_ZIP", get_glowroot_zip(args, glowroot_zip, glowroot)), ] env = dict((k, v) for (k, v) in [pair for pair in env_pairs if pair] if v is not None) From 969633447a3095e898473d4036f9cf3460a27ee2 Mon Sep 17 00:00:00 2001 From: cgbautista Date: Wed, 8 Oct 2025 13:21:22 +0200 Subject: [PATCH 06/11] Added an option in the docker-compose.yml to ensure there is no "search" domain in the /etc/resolv.conf copied onto the containers This avoids the `core` container trying to determine when the `data` container has finished its execution via `curl` to get responses from any `data.search_domain` machine that might exist. --- src/d2_docker/docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/d2_docker/docker-compose.yml b/src/d2_docker/docker-compose.yml index 36a1ed7..1b8eda2 100644 --- a/src/d2_docker/docker-compose.yml +++ b/src/d2_docker/docker-compose.yml @@ -29,6 +29,7 @@ services: ports: - "${DHIS2_CORE_DEBUG_PORT}" - "${GLOWROOT_PORT}" + dns_search: . db: image: "postgis/postgis:${POSTGIS_VERSION:-14-3.2-alpine}" shm_size: 1gb From 9baa64e88f07277a11dbfe8acd672977e0dcf1f0 Mon Sep 17 00:00:00 2001 From: cgbautista Date: Fri, 10 Oct 2025 17:22:17 +0200 Subject: [PATCH 07/11] Moved 4 functions inside a condition to avoid reseting container folders to the original content (it didn't erase contents, but overwrote any change on those folders with the files' previous version) --- src/d2_docker/config/dhis2-core-start.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/d2_docker/config/dhis2-core-start.sh b/src/d2_docker/config/dhis2-core-start.sh index 4a55c5b..691af21 100755 --- a/src/d2_docker/config/dhis2-core-start.sh +++ b/src/d2_docker/config/dhis2-core-start.sh @@ -162,14 +162,14 @@ init_done() { run() { local host=$1 psql_port=$2 - setup_tomcat - copy_apps - copy_documents - copy_datavalues - if is_init_done; then - debug "Container: already configured. Skip DB load" + debug "Container: already configured. Skip DB load and keeping other changes" else + debug "Container: clean. Copying tomcat files and dhis folders" + setup_tomcat + copy_apps + copy_documents + copy_datavalues debug "Container: clean. Load DB" wait_for_postgres run_sql_files From a4b64328e752cd2001cd96d6d33c42435701a6e0 Mon Sep 17 00:00:00 2001 From: cgbautista Date: Mon, 20 Oct 2025 10:40:43 +0200 Subject: [PATCH 08/11] extracted setup_tomcat, since it will copy any dhis.conf or server.xml that is passed as arguments --- src/d2_docker/config/dhis2-core-start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d2_docker/config/dhis2-core-start.sh b/src/d2_docker/config/dhis2-core-start.sh index 691af21..83d9beb 100755 --- a/src/d2_docker/config/dhis2-core-start.sh +++ b/src/d2_docker/config/dhis2-core-start.sh @@ -162,11 +162,11 @@ init_done() { run() { local host=$1 psql_port=$2 + setup_tomcat if is_init_done; then debug "Container: already configured. Skip DB load and keeping other changes" else debug "Container: clean. Copying tomcat files and dhis folders" - setup_tomcat copy_apps copy_documents copy_datavalues From 029174ba9a9b07ebb76a5c8df1b44bb5eb1d0c73 Mon Sep 17 00:00:00 2001 From: cgbautista Date: Mon, 20 Oct 2025 12:55:23 +0200 Subject: [PATCH 09/11] Fix in tabs --- src/d2_docker/config/dhis2-core-start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d2_docker/config/dhis2-core-start.sh b/src/d2_docker/config/dhis2-core-start.sh index 83d9beb..508fcde 100755 --- a/src/d2_docker/config/dhis2-core-start.sh +++ b/src/d2_docker/config/dhis2-core-start.sh @@ -166,7 +166,7 @@ run() { if is_init_done; then debug "Container: already configured. Skip DB load and keeping other changes" else - debug "Container: clean. Copying tomcat files and dhis folders" + debug "Container: clean. Copying tomcat files and dhis folders" copy_apps copy_documents copy_datavalues From 07bc6a91d829c7d43e02fba0059a10144bb44bef Mon Sep 17 00:00:00 2001 From: cgbautista Date: Mon, 20 Oct 2025 15:18:54 +0200 Subject: [PATCH 10/11] After stopping the running containers, the command "docker compose ps -q" did not return any container, so a "-a" parameter is added to ensure all processes (even stopped) are returned --- src/d2_docker/commands/rm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d2_docker/commands/rm.py b/src/d2_docker/commands/rm.py index a645f52..b619d26 100644 --- a/src/d2_docker/commands/rm.py +++ b/src/d2_docker/commands/rm.py @@ -15,7 +15,7 @@ def run(args): def remove_image(image): utils.logger.info("Delete image/containers: {}".format(image)) utils.run_docker_compose(["stop"], image) - result = utils.run_docker_compose(["ps", "-q"], data_image=image, capture_output=True) + result = utils.run_docker_compose(["ps", "-aq"], data_image=image, capture_output=True) container_ids = result.stdout.decode("utf-8").splitlines() utils.logger.debug("Container IDs: {}".format(container_ids)) if container_ids: From c394814452c96bba8a9f5af2a74c1d5926ceab89 Mon Sep 17 00:00:00 2001 From: cgbautista Date: Thu, 23 Oct 2025 10:56:52 +0200 Subject: [PATCH 11/11] Fixed formatting and Readme --- README.md | 11 ++++++----- src/d2_docker/config/dhis2-core-entrypoint.sh | 2 +- src/d2_docker/glowroot.py | 3 ++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 08db6a6..77db90d 100644 --- a/README.md +++ b/README.md @@ -382,13 +382,14 @@ $ curl -sS 'http://localhost:5000/harbor/https://docker.eyeseetea.com/api/v2.0/q ## Glowroot Glowroot is an open-source Java APM (Application Performance Monitoring) tool. It can help detect and diagnose application performance problems, tracing slow requests, errors, response time breakdowns, SQL capture and more. -When starting a container, there are a few options to enable glowroot on the Tomcat process: -- Use option `--glowroot-port=PORT` to specify the APM glowroot port of the Tomcat process. -- Use option `--glowroot` to use the latest version of glowroot in the Tomcat process. -- Use option `--glowroot-zip=FILE` to specify the zip file with a version of glowroot to run in the Tomcat process. +When starting a container, there are two options to enable glowroot on the Tomcat process: +- Use option `--glowroot` to use the latest version of glowroot in the Tomcat process. This requires internet access to be able to retrieve the file. +- Use option `--glowroot-zip=FILE` to specify the zip file with the version of glowroot to run in the Tomcat process. This takes precedence over the other option. +When enabling glowroot, it will start listening on port 4000/tcp so you can connect via browser to its interface. You may override this port with: +- `--glowroot-port=PORT` to specify the APM glowroot port. ### Run d2-docker with glowroot enabled in the default port at the latest version available ``` $ d2-docker start docker.eyeseetea.com/eyeseetea/dhis2-data:2.37.9-sierra --glowroot -``` \ No newline at end of file +``` diff --git a/src/d2_docker/config/dhis2-core-entrypoint.sh b/src/d2_docker/config/dhis2-core-entrypoint.sh index 45b9a0a..ffc3a3f 100755 --- a/src/d2_docker/config/dhis2-core-entrypoint.sh +++ b/src/d2_docker/config/dhis2-core-entrypoint.sh @@ -49,7 +49,7 @@ wait_for_data_container_to_finish_copy() { setup_glowroot() { if [ -f $GLOWROOT_ZIP ] && [ ! -d $GLOWROOT_DIR ] ; then status=0 - output=$(unzip -q "$GLOWROOT_ZIP" -d /opt/ 2>&1) || status=$? + output=$(unzip -q "$GLOWROOT_ZIP" -d /opt/ 2>&1) || status=$? # Ignore RC=1 that implies only warnings and no errors (like an empty zip file) if [ $status -gt 1 ]; then echo "$output" diff --git a/src/d2_docker/glowroot.py b/src/d2_docker/glowroot.py index 34a99d7..a5a542f 100644 --- a/src/d2_docker/glowroot.py +++ b/src/d2_docker/glowroot.py @@ -21,7 +21,6 @@ def get_latest_glowroot_url(): def get_glowroot_zip(command, glowroot_zip, glowroot): logger = utils.logger - glowroot_path=None if isinstance(command, list) and command[0] == "up": glowroot_file = tempfile.NamedTemporaryFile(delete=False, prefix="glowroot_", suffix=".zip", dir="/tmp") glowroot_path = glowroot_file.name @@ -38,6 +37,8 @@ def get_glowroot_zip(command, glowroot_zip, glowroot): # empty zipfile with zipfile.ZipFile(glowroot_path, mode="w") as zf: pass + else: + glowroot_path = None return utils.get_absfile_for_docker_volume(glowroot_path)