-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from filiperochalopes/develop
Add database cloud backup feature [Google Drive]
- Loading branch information
Showing
17 changed files
with
268 additions
and
7 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
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,7 @@ | ||
POSTGRES_DB='esus' | ||
POSTGRES_USER='postgres' | ||
POSTGRES_PASSWORD='esus' | ||
POSTGRESQL_PORT=54351 | ||
APP_PORT=88 | ||
PGWEB_PORT=8099 | ||
TIMEZONE='America/Bahia' |
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
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
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
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
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,29 @@ | ||
FROM python:alpine3.16 | ||
|
||
# instalando dependências para o container | ||
RUN apk add --no-cache postgresql-client tzdata curl | ||
|
||
ARG TIMEZONE | ||
|
||
# Configurando timezone | ||
RUN ls /usr/share/zoneinfo | ||
RUN cp "/usr/share/zoneinfo/${TIMEZONE}" /etc/localtime | ||
RUN echo "${TIMEZONE}" > /etc/timezone | ||
RUN date | ||
RUN apk del tzdata | ||
|
||
# Copiando arquivos de uso do cron | ||
ADD crontab.txt /crontab.txt | ||
ADD script.sh /script.sh | ||
COPY entry.sh /entry.sh | ||
RUN chmod 755 /script.sh /entry.sh | ||
RUN /usr/bin/crontab /crontab.txt | ||
|
||
# Criando o cenário para rodar a aplicação python | ||
WORKDIR /home | ||
COPY app . | ||
COPY wsgi.py / | ||
RUN pip install -r requirements.txt | ||
|
||
WORKDIR / | ||
CMD ["/entry.sh"] |
Empty file.
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,91 @@ | ||
from __future__ import print_function | ||
from datetime import datetime | ||
|
||
import os | ||
import sys | ||
from flask import Flask, Response | ||
|
||
import os.path | ||
from googleapiclient.discovery import build | ||
from googleapiclient.http import MediaFileUpload | ||
from googleapiclient.errors import HttpError | ||
|
||
from .env import BACKUP_EXPIRATION_TIME, DATABASE_HOST, DATABASE_NAME, DATABASE_USER, FILENAME, GOOGLE_DRIVE_FOLDER_ID, FILE_EXTENSION | ||
from .googleoauth import get_google_credentials | ||
|
||
app = Flask(__name__) | ||
|
||
def get_file_in_path(filename): | ||
return os.path.join(os.path.dirname(os.path.realpath(__file__)), filename) | ||
|
||
def upload_file(service, filename, mime_type, folder_id): | ||
try: | ||
file_metadata = { | ||
'name': filename, | ||
'parents': [folder_id], | ||
'mimeType': mime_type | ||
} | ||
|
||
media = MediaFileUpload(get_file_in_path(filename), mimetype=mime_type, resumable=True) | ||
|
||
file = service.files().create( | ||
body=file_metadata, | ||
media_body=media, | ||
fields='id' | ||
).execute() | ||
except HttpError as error: | ||
print(f'An error occurred: {error}') | ||
file = None | ||
|
||
return file.get('id') | ||
|
||
@app.route("/backup-database") | ||
def backup_database(): | ||
from sh import pg_dump | ||
|
||
print('Realizando backup do banco de dados...', file=sys.stderr) | ||
pg_dump('--host', DATABASE_HOST, '--port', '5432', '-U', DATABASE_USER, '-w', '--format', 'custom', '--blobs', '--encoding', | ||
'UTF8', '--no-privileges', '--no-tablespaces', '--no-unlogged-table-data', '--file', f'/home/{FILENAME}', DATABASE_NAME) | ||
|
||
|
||
# upload de arquivo | ||
print('Autenticando no Google...', file=sys.stderr) | ||
service = build('drive', 'v3', credentials=get_google_credentials()) | ||
|
||
print('Realizando upload para Google Drive...', file=sys.stderr) | ||
file_id = upload_file(service=service, filename=FILENAME, mime_type='application/octet-stream', folder_id=GOOGLE_DRIVE_FOLDER_ID) | ||
print('File uploaded:', file_id) | ||
|
||
# Google Drive API: https://developers.google.com/drive/api/v3/reference | ||
print('Listando arquivos na pasta de backup...', file=sys.stderr) | ||
# fields props: https://developers.google.com/drive/api/v3/reference/files | ||
# query props: https://developers.google.com/drive/api/guides/search-files#python | ||
results = service.files().list(q=f'"{GOOGLE_DRIVE_FOLDER_ID}" in parents and trashed = false', orderBy='createdTime desc', | ||
pageSize=20, fields="nextPageToken, files(id, name, mimeType, description, trashed)").execute() | ||
items = results.get('files', []) | ||
|
||
if not items: | ||
print('No files found.', file=sys.stderr) | ||
return | ||
else: | ||
for item in items: | ||
print('{:<40} {:<20} {:<20}'.format(item['name'], item['mimeType'], item['trashed']), file=sys.stderr) | ||
|
||
print('Excluindo arquivos antigos...', file=sys.stderr) | ||
for item in items: | ||
filename_datetime = item['name'].replace(FILE_EXTENSION, '') | ||
try: | ||
print(datetime.now()) | ||
print(BACKUP_EXPIRATION_TIME) | ||
if datetime.strptime(filename_datetime, '%Y_%m_%d_%H_%M_%S') < BACKUP_EXPIRATION_TIME: | ||
filename = f'{filename_datetime}{FILE_EXTENSION}' | ||
print(f'Excluindo {filename}', file=sys.stderr) | ||
os.remove(get_file_in_path(filename)) | ||
service.files().delete(fileId=item['id']).execute() | ||
except Exception as e: | ||
print('error', e) | ||
|
||
return Response('Backup realizado', status=201) | ||
|
||
if __name__ == '__main__': | ||
get_google_credentials() |
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,13 @@ | ||
from datetime import datetime, timedelta | ||
import os | ||
|
||
DATABASE_HOST = os.getenv('POSTGRES_HOST', 'psql') | ||
DATABASE_NAME = os.getenv('POSTGRES_DB', 'esus') | ||
DATABASE_USER = os.getenv('POSTGRES_USER', 'postgres') | ||
|
||
NOW = datetime.now() | ||
FILE_EXTENSION = '.backup' | ||
FILENAME = f'{NOW.strftime("%Y_%m_%d_%H_%M_%S")}{FILE_EXTENSION}' | ||
|
||
GOOGLE_DRIVE_FOLDER_ID = os.getenv('GOOGLE_DRIVE_FOLDER_ID', '1osoeAhww2IM2V2W_xbgcRoROHEk_DAPw') | ||
BACKUP_EXPIRATION_TIME = datetime.now() - timedelta(days=7) |
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,43 @@ | ||
from __future__ import print_function | ||
|
||
import os.path | ||
|
||
from google.auth.transport.requests import Request | ||
from google.oauth2.credentials import Credentials | ||
from google_auth_oauthlib.flow import InstalledAppFlow | ||
|
||
# If modifying these scopes, delete the file token.json. | ||
SCOPES = [ | ||
'https://www.googleapis.com/auth/drive.appdata', | ||
'https://www.googleapis.com/auth/drive.file', | ||
'https://www.googleapis.com/auth/drive.install', | ||
'https://www.googleapis.com/auth/drive', | ||
'https://www.googleapis.com/auth/drive.metadata.readonly' | ||
] | ||
|
||
CREDEDNTIALS = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'credentials.json') | ||
TOKEN = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'token.json') | ||
|
||
def get_google_credentials(): | ||
creds = None | ||
# The file token.json stores the user's access and refresh tokens, and is | ||
# created automatically when the authorization flow completes for the first | ||
# time. | ||
if os.path.exists(TOKEN): | ||
creds = Credentials.from_authorized_user_file(TOKEN, SCOPES) | ||
# If there are no (valid) credentials available, let the user log in. | ||
if not creds or not creds.valid: | ||
if creds and creds.expired and creds.refresh_token: | ||
creds.refresh(Request()) | ||
else: | ||
flow = InstalledAppFlow.from_client_secrets_file(CREDEDNTIALS, SCOPES) | ||
creds = flow.run_local_server(host='localhost', port=8080, open_browser=False) | ||
# Save the credentials for the next run | ||
with open(TOKEN, 'w') as token: | ||
token.write(creds.to_json()) | ||
|
||
return creds | ||
|
||
|
||
if __name__ == '__main__': | ||
get_google_credentials() |
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 @@ | ||
Flask==2.2.2 | ||
gunicorn==20.1.0 | ||
sh==1.14.3 | ||
google-api-python-client | ||
google-auth-httplib2 | ||
google-auth-oauthlib |
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,3 @@ | ||
# m h dom mon dow user command | ||
* 0 * * * /script.sh >> /var/log/script.log | ||
|
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 @@ | ||
#!/bin/sh | ||
|
||
# start python app | ||
gunicorn --bind 0.0.0.0:5000 -D --enable-stdio-inheritance --capture-output --log-level debug --reload wsgi:app | ||
# start cron | ||
/usr/sbin/crond -f -l 8 |
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,5 @@ | ||
#!/bin/sh | ||
|
||
# code goes here. | ||
curl http://localhost:5000/backup-database | ||
echo "This is a script, run by cron!" |
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,4 @@ | ||
from home.app import app | ||
|
||
if __name__ == "__main__": | ||
app.run() |
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