Clone a dhis2 installation from another server. Supported:
- Remote server: tomcat.
- Local server: tomcat or d2-docker.
This program will perform several steps on a running DHIS2 server to transform it into a clone of a remote one.
The steps are:
- Stop the running tomcat/d2-docker.
- Backup the DHIS2 war file and database.
- Copy the webapps from the remote server into the local machine.
- Empty the local database and fill it with a replica of the remote one.
- Start the tomcat/d2-docker again.
Any step can be individually switched off (--no-backups,
--no-webapps, --no-db, --manual-restart, --use-backup).
Also, it can run some sql scripts on the database before starting the
server again (--post-sql). This is useful in several
scenarios. For example, to empty the tables that contain the data
(while keeping the metadata), as one would want for a training server
(see the empty_data_tables_228.sql example). Or it can be used to
automatically upgrade from one version to another (say, 2.29 to 2.30
by running upgrade-230.sql).
If it is so specified in the configuration file, it will perform some postprocessing actions once the server is running again (see section below).
All the commands run to perform the different steps are printed on the screen (with color to help identify the steps), and the output of those commands too. If any step fails, the program will signal an error and stop all the processing at that point.
Instances of type d2-docker might change its image (typically, in an upgrade) in the cloning process, so there is the concept of "transformed" images. Use options --stop-transformed to use config entry local_docker_image_stop_transformed and --start-transformed to use config entry local_docker_image_start_transformed instead of the default value local_docker_image.
sudo apt install pip3
pip install -r requirements.txtdhis2_clone.py [-h] [--db-local DB_LOCAL] [--db-remote DB_REMOTE] [--api-local-username API_LOCAL_USERNAME]
[--api-local-password API_LOCAL_PASSWORD] [--no-backups] [--no-webapps] [--no-db]
[--no-postprocess] [--no-preprocess] [--manual-restart] [--post-sql POST_SQL [POST_SQL ...]]
[--strict-sql] [--pre-api PRE_API] [--post-api POST_API] [--keep-temp] [--post-clone-scripts]
[--post-import] [--update-config] [--no-color] [--start-transformed] [--stop-transformed]
[--use-backup USE_BACKUP]
configpositional arguments:
config file with configuration
options:
-h, --help show this help message and exit --db-local DB_LOCAL db to be override --db-remote DB_REMOTE db to be copied in the db-local --api-local-username API_LOCAL_USERNAME api local user --api-local-password API_LOCAL_PASSWORD api local password --no-backups don't make backups --no-webapps don't clone the webapps --no-db don't clone the database --no-postprocess don't do postprocessing --no-preprocess don't do preprocessing --manual-restart don't stop/start tomcat --post-sql POST_SQL [POST_SQL ...] sql files to run post-clone --strict-sql stop the sql script on first fail and show in the log --pre-api PRE_API Pre Api calls compatible versions: 2.34 / 2.36 / 2.38 / 2.41 (default: 2.36) --post-api POST_API Post Api calls compatible versions: 2.34 / 2.36 / 2.38 / 2.41 (default: 2.36) --keep-temp Preserve temporary d2-docker files for cloning the instance --post-clone-scripts execute all py and sh scripts in post_clone_scripts_dir --post-import import to DHIS2 selected json files from post_process_import_dir --update-config update the config file --no-color don't use colored output --start-transformed Override d2-docker image for start --stop-transformed Override d2-docker image for stop --use-backup USE_BACKUP Path to remote backup file to use instead of making a remote pg_dump
To invoke the program you need to specify a configuration file, as in:
dhis2_clone config_training.json
An example configuration file is provided in this repository (configuration_example.json).
The sections in the configuration file are:
local_type: Local instance type. "tomcat" or "d2-docker".local_docker_image". Docker image to use (example: "eyeseetea/dhis2-data:2.32-sierra-leone").local_docker_image_stop_transformed. If--stop-transformedoptions is used, then instead of usinglocal_docker_image, it will use entrylocal_docker_image_stop_transformed. This "stop" action is then used in the following d2-docker commands: stop_tomcat -> d2-docker stop, backup_db -> d2-docker copy, get_db -> d2-docker create data. "local_docker_image_start_transformed": If--start-transformedoptions is used, then instead of usinglocal_docker_image, it will use entrylocal_docker_image_start_transformed. This "start" action is then used in the following d2-docker commands: start_tomcat -> d2-docker start.local_docker_port: Docker port.local_docker_deploy_path: Docker instance deploy path namespace.backups_dir: directory where it will store the backups.backup_name: an identifier that it will append to the name of the war file and database backups.server_dir_local: base directory of the tomcat running in the local server. Although server_dir_local points to the Tomcat base directory, it is also used internally as a temporary directory by d2-docker. When running a d2-docker cloning operation, this temporary directory will be removed by default (unless you use the --keep-temp option).
If this path is set to a critical location (such as your home directory or any folder with important files), you risk losing data. Only the d2-docker temporary files are intended to be removed, but the behavior can be misleading.
* server_dir_remote: base directory of the tomcat running in the
remote server.
hostname_remote: name or IP of the machine containing the remote DHIS2 instance. The user running the script is assumed to have ssh access to that machine.db_local: URI conninfo string to connect to the local database.db_remote: URI conninfo string to connect to the remote database.war_local: name of the local war file (when connecting to the web server, this corresponds to the last part of the URL - for example, if it isdhis2-demo.war, the webserver will respond athttps://.../dhis2-demo).war_remote: name of the remote war file.docker_temp_folder: Base folder for the docker creation temp folders.api_local: if some post-processing steps are applied, this section needs to define as params the username and passwordurl,usernameandpasswordto connect to the running DHIS2 system after the cloning.postprocess: list of blocks, each containing users (specified byselectUsernamesand/orselectFromGroups) and anactionto perform on them (activateto activate them,deleteOthersto keep them in exclusive,addRolesto specify a list of extra roles to give, oraddRolesFromTemplateto give a reference username whose roles we want to add). Instead of a block, you can give a url, and the blocks contained in that url will be added to the list of blocks.preprocess: list of blocks, each containing actions for each department (specified indepartments) All the rules will create a sql file to execute after launch tomcat. In the case of edit a department metadata, you should include the metadata type inselectMetadataTypethe departmentselectDepartament, and theaction, for example anonymizeData or deleteData and the list of metadata: selectDatasets, selectTrackedEntityAttributes, selectDataElements, Valid options: dataSets, programs, trackerPrograms. Format: ["dataSets"] Examples:- {
"selectDepartament": "NTD", "selectMetadataType": ["trackerPrograms","eventPrograms","dataSets"], "selectDatasets": [
"tnek2LjfuIm", "zna8KfLMXn4", "XBgvNrxpcDC", "WHPEpoVDFFv", "SAV16xEdCZW", "AAYgHGENgbF", "NKWbkXyfO5F", "oVxjBKA1Yzu", "S1UMweeoPsi", "s3iaozBY0dv", "JP4bMwvJ6oU", "U5ejGQdX4Ih"
], "action": "removeData"
}
selectEventProgram or selectTrackerProgram to filter the event programs or tracker programs.1 You could also filter by
"selectOrgUnitAndDescendants": ["example_uid"], "selectDataElements": ["example_uid"], "selectOrgUnits": ["example_uid"],
You can also remove organisationunits using the action:
removeOrganisationUnitTreeyou must add the organisationunit uids: selectOrganisationUnit: ["uid","uid2"] orremoveOrganisationUnitTreeByLevel(needs a level attribute, like level:3). Examples:- {
"selectDepartament": "All", "selectMetadataType": ["organisationUnits"], "selectOrganisationUnit": [ "hmZE3mVAZFf", "G3thRWUQAX9", "HfVjCurKxh2", "seHJdofSPcM" ], "action": "removeOrganisationUnitTree"
}, {
"selectDepartament": "All", "selectMetadataType": ["organisationUnits"], "level": 3, "action": "removeOrganisationUnitTreeByLevel"
}
- To anonymizeData you should use the action "anonymizeData" and could add the following params
- {
"selectDepartament": "NTD", "selectMetadataType": ["trackerPrograms"], "anonymizePhone": true, "anonymizeMail": true, "anonymizeOrgUnit": true, "anonymizeCoordinates": true, "selectTrackedEntityAttributes": ["oTvXfEywjT3", "n8E6WIyAwcC", "DwZNiXy5Daz", "FHw1NKy0PWY", "eQtZaLIO3XU",
"na3ZJRtjpGH", "HkBG3DVELBM", "sKBh0kazOCk", "AAkZm4ZxFw7", "ENRjVGxVL6l", "aBaYLJryaMr", "iy884aJfYTc"],
"action": "anonymizeData"
}, {
"selectDepartament": "HWF", "selectMetadataType": ["dataSets"], "action": "anonymizeData"
},
- To anonimize users except some of them, you should fill the follow rule:
- {
"selectDepartament": "ALL", "selectAdminUser": "newadmin", "excludeUsernames": [
"oldadmin", "oldadmin2"
], "selectOldAdminUser": "oldadmin", "action": "anonymizeUsers" }
to perform on them (
activateto activate them,deleteOthersto keep them in exclusive,addRolesto specify a list of extra roles to give, oraddRolesFromTemplateto give a reference username whose roles we want to add). Instead of a block, you can give a url, and the blocks contained in that url will be added to the list of blocks.removeUnlistedData: deletes ALL data for non-listed items in the departament list of programs/dataset uids. - For tracker/event programs: removes events, enrollments, and trackedEntityInstances from every program not present in the departament metadata list. - For aggregate datasets: removes dataValues from every dataset not present in the departament metadata list.- Example:
- {
"action": "removeUnlistedData" }
showDataSummary: displays data counts grouped by program and dataset at the end of preprocess.sql execution.Example: {
"action": "showDataSummary"
}
You may want to run the cloning script periodically. For that, you can use the appropriate users's crontab:
crontab -eFor example, this will run the cloning for a training server every Saturday night at 22:00:
$ crontab -l 00 22 * * 6 /usr/local/bin/dhis2_clone --post-sql /usr/share/dhis2_clone/empty_data_tables.sql /usr/share/dhis2_clone/training.json >> /var/log/dhis2_clone.log 2>&1
This program depends on a few Python standard modules and also:
psycopg2: to connect to the postgres database.requests: to make HTTP requests.
They are available already packaged in most distributions (normally
called python-psycopg2 and python-requests).
Also, it relies on two more modules included here:
process.py: includes all the post-processing logic.d2apy.py: handles communications with a DHIS2 server through its api.
Other than the standard system utilities, the program will need to have a local installation of:
rsync(used withsshto copy the remote webapps).ssh(used to copy the remote webapps and to launch the remote dump of the database to be cloned).psql(used to modify the local database).pg_dump(used to make a backup of the local database, and a dump of the remote one -- so this one needs to exist onhostname_remotetoo).zcat(used to read remote backup).
The program assumes that it runs with permissions to:
Read and write all the files in
<server_dir_local>, and especially,- run the files
<server_dir_local>/bin/startup.shand
<server_dir_local>/bin/shutdown.sh.- write on
<server_dir_local>/webappsand<server_dir_local>/files.
- run the files
Write on
<backups_dir>.Run
sshto connect to<hostname_remote>.Run
psqlandpg_dumpon the local host, and on<hostname_remote>thrussh.Read all the files in
<hostname_remote>:<server_dir_remote>thrussh.Have read and write access to the local database thru the
db_localconninfo string, and read access to the remote one thrudb_remote.Have read access to the remote backup file if
--use-backupis used.
If it runs any kind of postprocessing (by having an api_local and
postprocess section in the configuration file), it will also need
permissions to:
- Access the running dhis2 instance thru the
url,usernameandpasswordpresent in theapi_localsection, and have permissions to change the users. Using --api-local-username, --api-local-password params
In any case, it does not assume permissions to:
- Delete and create databases.
You can filter vi api version in the preprocess or proprocess, for example adding in the config file:
"pre_api": "2.36", "post_api": "2.34",
or adding as param pre-api/post-api apiversion