diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8722828 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.doit.db +__pycache__/ diff --git a/dodo.py b/dodo.py new file mode 100644 index 0000000..f67652b --- /dev/null +++ b/dodo.py @@ -0,0 +1,101 @@ +import subprocess + +from doit.tools import LongRunning + +from dodo_utils import wait_net_service, up2date_anyimages + +COMPOSE = 'docker-compose -p feedati' + + +def task_build(): + '''builda il container docker''' + return { + 'uptodate': [up2date_anyimages], + 'file_dep': ['docker-compose.yml', 'docker/Dockerfile-tt-rss'], + 'actions': [COMPOSE + ' build'], + 'clean': [remove_build], + } + + +def remove_build(): + cmd = "docker container ls -a --format '{{.ID}}\t{{.Names}}'|" \ + "awk '$2 ~ /feedati_/ { print $$1 }' | " \ + "xargs -r docker container rm", + subprocess.check_call(cmd, shell=True) + + +def task_build_rm(): + '''rimuove container avviati''' + return {'actions': [remove_build]} + + +def task_build_rmi(): + '''rimuove immagini ottenute con build''' + return { + 'actions': [ + r"docker images |" + "awk '$1 ~ /^feedati\// { print $3 }' | xargs -r " + "docker rmi", + ] + } + + +def task_dump_rm(): + '''rimuove il dump caricato sul db''' + return { + 'actions': [ + "docker container ls -a --format '{{.ID}}\t{{.Names}}'|" + "awk '$2 ~ /^feedati_db { print $$1 }' | " + "xargs -r docker container rm", + + "docker volume rm feedati_postgres_data || true", + ] + } + + +def task_dump_load(): + '''applica il dump sql al container del db''' + return { + 'task_dep': ['dump_rm', 'build'], + 'file_dep': ['docker/ttrss.sql'], + 'actions': [ + (COMPOSE + ' up -d db').split(), + r'docker cp ./docker/ttrss.sql ' + '$(docker ps -qf name=feedati_db):/tmp/ttrss.sql', + (wait_net_service, ['localhost', 5432, 300]), + r'docker exec -t $(docker ps -qf name=feedati_db) ' + 'su -c "psql -d ttrss < /tmp/ttrss.sql" postgres', + 'docker exec -t $(docker ps -qf name=feedati_db) ' + 'rm -f /tmp/ttrss.sql', + COMPOSE + ' stop', + ] + } + + +def task_fix_perms(): + '''fix permissions for shared www dir''' + return { + 'actions': [ + 'chmod -R 777 tt-rss/feed-icons/ tt-rss/cache/ tt-rss/lock/' + .split() + ] + } + + +def task_up(): + return { + 'task_dep': ['build', 'dump_load', 'fix_perms'], + 'actions': [LongRunning( + (COMPOSE + ' up'), + shell=True) + ] + } + + +def task_cleanall(): + '''clean everything there is to clean''' + return { + 'task_dep': ['build_rm', 'build_rmi', 'dump_rm'], + 'actions': None + } + diff --git a/dodo_utils.py b/dodo_utils.py new file mode 100644 index 0000000..52295dd --- /dev/null +++ b/dodo_utils.py @@ -0,0 +1,46 @@ +import subprocess + +def wait_net_service(server, port, timeout=None): + """ Wait for network service to appear + @param timeout: in seconds, if None or 0 wait forever + @return: True of False, if timeout is None may return only True or + throw unhandled network exception + """ + import socket + import errno + + s = socket.socket() + if timeout: + from time import time as now + # time module is needed to calc timeout shared between two exceptions + end = now() + timeout + + while True: + try: + if timeout: + next_timeout = end - now() + if next_timeout < 0: + return False + else: + s.settimeout(next_timeout) + s.connect((server, port)) + except socket.timeout as err: + # this exception occurs only if timeout is set + if timeout: + return False + except socket.error as err: + # catch timeout exception from underlying network library + # this one is different from socket.timeout + if type(err.args) != tuple or err[0] != errno.ETIMEDOUT: + raise + else: + s.close() + return True + + +def up2date_anyimages(): + cmd = "docker images -q feedati/*".split() + output = subprocess.check_output(cmd).strip() + if output: + return True + return False