-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
noxowl
committed
Sep 18, 2020
0 parents
commit 3e8e846
Showing
11 changed files
with
989 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
.DS_Store | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
FROM python:3.8-slim | ||
|
||
RUN apt-get update && \ | ||
apt-get install -y --no-install-recommends \ | ||
ca-certificates \ | ||
&& apt-get clean && \ | ||
rm -rf /var/lib/apt/lists/* | ||
|
||
ENV APP_DIR /app | ||
|
||
WORKDIR ${APP_DIR} | ||
|
||
COPY Pipfile Pipfile.lock ${APP_DIR}/ | ||
|
||
RUN pip install pipenv --no-cache-dir && \ | ||
pipenv install --system --deploy && \ | ||
pip uninstall -y pipenv virtualenv-clone virtualenv && \ | ||
mkdir ${APP_DIR}/logs && \ | ||
mkdir /srv/origin | ||
|
||
COPY . ${APP_DIR}/ | ||
|
||
ENV DROPBOX_BACKUP_ACCESS_TOKEN "" | ||
ENV DROPBOX_BACKUP_WRITE_MODE "overwrite" | ||
ENV DROPBOX_BACKUP_FROM /srv/origin | ||
ENV DROPBOX_BACKUP_TO /backup | ||
ENV DROPBOX_BACKUP_DEBUG_MODE false | ||
ENV DROPBOX_BACKUP_TEST_MODE false | ||
|
||
CMD ["python", "-c", "from dropbox_backup import app; app.execute();"] |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
[[source]] | ||
name = "pypi" | ||
url = "https://pypi.org/simple" | ||
verify_ssl = true | ||
|
||
[dev-packages] | ||
|
||
[packages] | ||
dropbox = "*" | ||
|
||
[requires] | ||
python_version = "3.8" |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Dropbox Backup | ||
|
||
Create tar.gz archive and upload to Dropbox. | ||
|
||
## Usage | ||
|
||
### Build | ||
<code> | ||
docker build -t noxowl/dropbox-backup:latest . | ||
</code> | ||
|
||
### Run | ||
<code> | ||
docker run -it --name dropbox-backup -e DROPBOX_BACKUP_ACCESS_TOKEN="YOUR_TOKEN" -e DROPBOX_BACKUP_TO="YOUR_DROPBOX_APP_FOLDER_PATH" -v [ORIGIN_PATH]:/srv/origin noxowl/dropbox-backup:latest | ||
</code> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# -*- coding: utf-8 -*- | ||
""" | ||
dropbox_backup | ||
""" | ||
|
||
__version__ = '1.0' | ||
|
||
from .dropbox_backup import app |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import os | ||
import sys | ||
import logging | ||
from .packer import BackupPacker | ||
from .transporter import DropboxTransporter | ||
from .logger import get_logger | ||
|
||
|
||
def is_true(value) -> bool: | ||
return value.lower() == 'true' | ||
|
||
|
||
class DropboxBackup: | ||
def __init__(self): | ||
self.backup = None | ||
self.dropbox = None | ||
self.is_debug = is_true(os.environ['DROPBOX_BACKUP_DEBUG_MODE']) | ||
logging.basicConfig( | ||
filename='logs/backup.log', | ||
level=logging.DEBUG if self.is_debug else logging.INFO) | ||
self.logger = get_logger(__name__) | ||
self.is_test = is_true(os.environ['DROPBOX_BACKUP_TEST_MODE']) | ||
self.access_token = os.environ['DROPBOX_BACKUP_ACCESS_TOKEN'] | ||
self.dropbox_write_mode = os.environ['DROPBOX_BACKUP_WRITE_MODE'] | ||
self.backup_from = os.environ['DROPBOX_BACKUP_FROM'] | ||
self.backup_to = os.environ['DROPBOX_BACKUP_TO'] | ||
self.backup_basename = os.path.basename(self.backup_to) | ||
self.pack_to = '/tmp/{0}.tar.gz'.format(self.backup_basename) | ||
|
||
def initialize(self): | ||
self.logger.info('Dropbox Backup Initialize Started.') | ||
self.backup = BackupPacker( | ||
pack_from=self.backup_from, | ||
pack_to=self.pack_to, | ||
basename=self.backup_basename | ||
) | ||
self.dropbox = DropboxTransporter( | ||
access_token=self.access_token, | ||
write_mode=self.dropbox_write_mode, | ||
autorename=False | ||
) | ||
self.dropbox.connection_check() | ||
self.logger.info('Dropbox Backup Initialized.') | ||
|
||
def dry_run(self): | ||
self.backup.run() | ||
|
||
def run(self): | ||
self.backup.run() | ||
self.dropbox.upload(self.pack_to, self.backup_to + '.tar.gz') | ||
|
||
def execute(self): | ||
self.initialize() | ||
if self.is_test: | ||
self.dry_run() | ||
else: | ||
self.run() | ||
self.logger.info('Job finished. Exit.') | ||
sys.exit() | ||
|
||
|
||
app = DropboxBackup() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import logging | ||
|
||
|
||
def get_logger(module_name): | ||
logger = logging.getLogger(module_name) | ||
stream = logging.StreamHandler() | ||
logger.addHandler(stream) | ||
return logger |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import os | ||
import tarfile | ||
import shutil | ||
from .logger import get_logger | ||
|
||
|
||
def dir_size(root_path): | ||
total = 0 | ||
for path, dirs, files in os.walk(root_path): | ||
for file in files: | ||
filepath = os.path.join(path, file) | ||
total += os.path.getsize(filepath) | ||
return total | ||
|
||
|
||
class BackupPacker: | ||
def __init__(self, pack_from: str, pack_to: str, basename): | ||
self.logger = get_logger(__name__) | ||
self.pack_from = pack_from | ||
self.pack_to = pack_to | ||
self.backup_basename = basename | ||
self.temp_path = '/tmp/origin' | ||
|
||
def copy_origin(self) -> None: | ||
self.logger.info('coping original file...') | ||
shutil.copytree(self.pack_from, self.temp_path) | ||
for file in os.listdir(self.temp_path): | ||
os.chown(os.path.join(self.temp_path, file), uid=1000, gid=1000) | ||
self.logger.info('original file copied.') | ||
self.logger.debug(os.listdir(self.temp_path)) | ||
|
||
def make_tar(self) -> None: | ||
self.logger.info('initiate packing.') | ||
with tarfile.open(self.pack_to, "w:gz") as tar: | ||
for file in os.listdir(self.temp_path): | ||
tar.add( | ||
'{0}/{1}'.format(self.temp_path, file), | ||
arcname='{0}/{1}'.format(self.backup_basename, os.path.basename(file)), | ||
recursive=False, | ||
filter=self._filter | ||
) | ||
if not os.path.exists(self.pack_to): | ||
self.logger.error('Packed file not exist. abort.') | ||
raise FileNotFoundError | ||
else: | ||
self.logger.info('Packed file {0} is successfully created in {1} → {2} byte'.format( | ||
self.backup_basename, | ||
self.pack_to, | ||
os.path.getsize(self.pack_to) | ||
)) | ||
|
||
def _filter(self, tarinfo: tarfile.TarInfo): | ||
if tarinfo.isdir(): | ||
self.logger.info( | ||
'pack {0} → {1} byte'.format( | ||
tarinfo.name, | ||
dir_size(os.path.join(self.temp_path, os.path.basename(tarinfo.name))) | ||
) | ||
) | ||
else: | ||
self.logger.info( | ||
'pack {0} → {1} byte'.format( | ||
tarinfo.name, | ||
tarinfo.size) | ||
) | ||
return tarinfo | ||
|
||
def run(self): | ||
self.copy_origin() | ||
self.make_tar() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import dropbox | ||
from .logger import get_logger | ||
|
||
mode = { | ||
'add': 'add', | ||
'overwrite': 'overwrite', | ||
'update': 'update' | ||
} | ||
|
||
|
||
class DropboxTransporter: | ||
def __init__(self, access_token: str, write_mode: str, autorename: bool): | ||
self.logger = get_logger(__name__) | ||
self.access_token = access_token | ||
self.dropbox_session = dropbox.Dropbox(self.access_token) | ||
self.autorename = autorename | ||
try: | ||
self.write_mode = dropbox.files.WriteMode(mode[write_mode]) | ||
except KeyError: | ||
self.logger.error('Please input the correct Write Mode. [add/overwrite/update]') | ||
raise KeyError | ||
|
||
def upload(self, file, file_to) -> None: | ||
self.logger.info('initiate dropbox upload.') | ||
with open(file, 'rb') as f: | ||
self.dropbox_session.files_upload( | ||
f.read(), | ||
file_to, | ||
mode=self.write_mode, | ||
autorename=self.autorename) | ||
self.logger.info('dropbox upload finished.') | ||
|
||
def connection_check(self) -> None: | ||
payload = 'ping' | ||
echo = self.dropbox_session.check_user(payload) | ||
self.logger.debug(echo) | ||
if echo.result != payload: | ||
self.logger.error('Dropbox connection failed.') | ||
raise ConnectionError | ||
else: | ||
self.logger.error('Dropbox connection success.') |