├── .gitattributes ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── data └── README.md ├── docker-compose.yml ├── metabase-db-clean.sql ├── requirements.txt └── run.xsh /.gitattributes: -------------------------------------------------------------------------------- 1 | *.xsh text linguist-language=Python 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | data/metabase 2 | data/*.sql -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM metabase/metabase:v0.36.6 2 | RUN apk update && apk add --update py-pip && pip install xonsh==0.9.24 3 | ADD run.xsh / 4 | RUN chmod +x run.xsh 5 | ENTRYPOINT ["/usr/bin/xonsh", "/run.xsh"] 6 | 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, anki-code 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | metabase-sql-wrapper is a Docker container based on the Metabase container. It automatically saves the Metabase H2 database to an SQL file when the container stops and recreates the H2 database from the SQL file when the container starts (if the database does not already exist). 3 |
4 | 5 |
6 | This allows to save the Metabase H2 database SQL-file to Git, versioning changes
and restore the database from SQL-file.
7 |
10 | If you like the idea click ⭐ on the repo and stay tuned. 11 |
12 | 13 | ## Run container 14 | ```shell script 15 | git clone https://github.com/anki-code/metabase-sql-wrapper 16 | cd metabase-sql-wrapper 17 | docker-compose up 18 | ``` 19 | 20 | ## How it works 21 | 22 | 1. [`docker-compose.yml`](https://github.com/anki-code/metabase-sql-wrapper/blob/master/docker-compose.yml) file has environment variables: 23 | 24 | ```shell script 25 | MB_DB_FILE: /data/metabase 26 | MB_DB_INIT_SQL_FILE: /data/metabase.db.sql # (optional) used to build the DB if MB_DB_FILE doesn't exists 27 | MB_DB_SAVE_TO_SQL_FILE: /data/metabase.db.sql # (optional) used to save SQL when container was stopped 28 | ``` 29 | 30 | 2. `docker-compose up` runs `run.xsh` with [xonsh shell](https://xon.sh/) wrapper that catches 31 | the docker signals and environment variables and do saving or creating the Metabase DB after stopping 32 | or before starting the container. 33 | 34 | 3. If `MB_DB_INIT_SQL_FILE` is set and `MB_DB_FILE` directory doesn't exists then before running Metabse 35 | the database will be created from the SQL-file. 36 | 37 | 4. If `MB_DB_SAVE_TO_SQL_FILE` is set and the container will get stop/restart signal then the database will be saved 38 | to SQL-file after Metabase has been stopped. 39 | 40 | This way you can run container, save your queries to Metabase, stop the container and commit it to Git. 41 | 42 | ## Cleaning the database before commit to Git 43 | 44 | By default Metabase writes logs and history to the database. To clean this before commit to Git you can 45 | use the [`metabase-db-clean.sql`](https://github.com/anki-code/metabase-sql-wrapper/blob/473f3fd23829216cc4384df3bbbda5a3dcd7eec6/metabase-db-clean.sql) script: 46 | ```bash 47 | java -cp metabase.jar org.h2.tools.RunScript -url jdbc:h2:./metabase.db -script /path/to/repository/metabase-db-clean.sql 48 | ``` 49 | 50 | ## Links 51 | 52 | * This container based on [docker-xonsh-wrapper](https://github.com/anki-code/docker-xonsh-wrapper) 53 | -------------------------------------------------------------------------------- /data/README.md: -------------------------------------------------------------------------------- 1 | Here will be the data: Metabase H2 database file and SQL-file. 2 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | metabase-sql-wrapper: 4 | build: . 5 | ports: 6 | - 3000:3000 7 | volumes: 8 | - ./data:/data 9 | environment: 10 | MB_DB_FILE: /data/metabase 11 | MB_DB_INIT_SQL_FILE: /data/metabase.db.sql 12 | MB_DB_SAVE_TO_SQL_FILE: /data/metabase.db.sql 13 | -------------------------------------------------------------------------------- /metabase-db-clean.sql: -------------------------------------------------------------------------------- 1 | SET DB_CLOSE_DELAY -1; 2 | DELETE FROM "PUBLIC"."TASK_HISTORY"; 3 | DELETE FROM "PUBLIC"."ACTIVITY" WHERE "TOPIC" != 'install'; 4 | DELETE FROM "PUBLIC"."QUERY_EXECUTION"; 5 | DELETE FROM "PUBLIC"."VIEW_LOG"; -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | xonsh -------------------------------------------------------------------------------- /run.xsh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env xonsh 2 | 3 | import subprocess, signal 4 | 5 | class Process: 6 | """ 7 | Process class catches the signals and wait for the process end or interrupt. 8 | """ 9 | stop_now = False 10 | def __init__(self, cmd): 11 | for s in [signal.SIGINT, signal.SIGTERM]: 12 | signal.signal(s, self.proc_terminate) 13 | 14 | proc = subprocess.Popen(cmd, shell=True) 15 | self.proc = proc 16 | self.pid = proc.pid 17 | proc.wait() 18 | 19 | def proc_terminate(self, signum, frame): 20 | echo @(f'*** CATCH: signum={signum}, stopping the process...') 21 | self.proc.terminate() 22 | self.stop_now = True 23 | 24 | if __name__ == '__main__': 25 | echo '*** Metabase SQL wrapper [https://github.com/anki-code/metabase-sql-wrapper]' 26 | 27 | metabase_jar = '/app/metabase.jar' 28 | 29 | metabase_db_path = __xonsh__.env.get('MB_DB_FILE', '/data/metabase') 30 | metabase_db_path = fp'{metabase_db_path}' 31 | 32 | metabase_db_path_exists = metabase_db_path.exists() 33 | if metabase_db_path_exists: 34 | echo @(f'*** Metabase DB path: {metabase_db_path}') 35 | else: 36 | mkdir -p @(metabase_db_path) 37 | echo @(f'*** Metabase DB path created: {metabase_db_path}') 38 | 39 | metabase_db_file = metabase_db_path / metabase_db_path.name 40 | 41 | init_sql_file = __xonsh__.env.get('MB_DB_INIT_SQL_FILE') 42 | 43 | if pf'{init_sql_file}'.exists(): 44 | if metabase_db_path_exists: 45 | echo @(f'*** Database path {metabase_db_path} exists, SKIP creating database from {init_sql_file}') 46 | else: 47 | echo @(f'*** Create database {metabase_db_file} from {init_sql_file}') 48 | java -cp @(metabase_jar) org.h2.tools.RunScript -url jdbc:h2:@(metabase_db_file) -script @(init_sql_file) 49 | echo '*** Creating DONE' 50 | else: 51 | echo @(f'*** MB_DB_INIT_SQL_FILE {init_sql_file} not found, SKIP') 52 | 53 | p = Process('/app/run_metabase.sh') 54 | 55 | save_sql_file = __xonsh__.env.get('MB_DB_SAVE_TO_SQL_FILE') 56 | if save_sql_file: 57 | echo @(f'*** Saving database {metabase_db_file} to {save_sql_file}') 58 | java -cp @(metabase_jar) org.h2.tools.Script -url jdbc:h2:@(metabase_db_file) -script @(save_sql_file) 59 | echo @('*** Saving DONE') 60 | --------------------------------------------------------------------------------