Skip to content

Commit

Permalink
add auto backup script for mysql database
Browse files Browse the repository at this point in the history
  • Loading branch information
fondoger committed Apr 27, 2019
1 parent bd15e73 commit 1005ee7
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 22 deletions.
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ python manage.py db init

**本地运行**

```
```bash
python manage.py runserver -h0.0.0.0 -p80
```

Expand All @@ -40,11 +40,17 @@ export flask_server_type="development"

启动服务,推荐使用[Gunicorn](http://gunicorn.org/),步骤如下:

```bash
gunicorn -w 3 manage:app -b 0.0.0.0:8000
```
gunicorn -w 3 manage:app -b 0.0.0.0:80
```

由于暂时基本没有静态文件的访问需求,故没有使用Nginx服务器。
第三步:

配置nginx,转发80端口请求到gunicorn:

```bash
sudo ln -s deployment/nginx /etc/nginx/sites-enabled/mysitename.conf
```

API设计及文档
-------
Expand Down
7 changes: 4 additions & 3 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
login_manager.login_view = 'api.login'
rank = Rank()


def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
Expand All @@ -34,7 +35,7 @@ def create_app(config_name):
rd.init_app(app)
login_manager.init_app(app)
task.init_app(app)
scheduler.init_app(app) # access scheduler from app.scheduler
scheduler.init_app(app) # access scheduler from app.scheduler

"""
Running in gunicorn:
Expand All @@ -43,8 +44,8 @@ def create_app(config_name):
Read: https://stackoverflow.com/questions/16053364
"""
if not app.debug or os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
# prevents scheduler start twice (only in debug mode)
# https://stackoverflow.com/questions/14874782
# prevents scheduler start twice (only in debug mode)
# https://stackoverflow.com/questions/14874782
scheduler.start()
add_init_jobs()
atexit.register(lambda: scheduler.shutdown())
Expand Down
2 changes: 2 additions & 0 deletions app/api/aliyun_mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import uuid
import requests



ActivationSubject = "欢迎注册,请验证您的邮箱"

ActivationText = """尊敬的用户,您好!
Expand Down
10 changes: 4 additions & 6 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@
class Config:
DEBUG = True

### For sqlalchemy
# For sqlalchemy
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'data-test.sqlite')
SQLALCHEMY_TRACK_MODIFICATIONS = False
SECRET_KEY = '123'
TRAP_BAD_REQUEST_ERRORS = False # For restful api
TRAP_HTTP_EXCEPTIONS = False

### For Flask-Redis
# For Flask-Redis
REDIS_URL = 'redis://localhost:6379/0'
### For Flask-RQ2
# For Flask-RQ2
RQ_REDIS_URL = REDIS_URL

### For APScheduler
# For APScheduler
SCHEDULER_API_ENABLED = True
SCHEDULER_API_PREFIX = "/t"
SCHEDULER_JOBSTORES = {
Expand All @@ -32,8 +32,6 @@ class Config:
@staticmethod
def init_app(app):
import logging
from logging import StreamHandler
#file_handler = StreamHandler()
file_handler = logging.FileHandler("app.log")
file_handler.setLevel(logging.DEBUG)
app.logger.addHandler(file_handler)
Expand Down
2 changes: 1 addition & 1 deletion deployment/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ server {
listen 80;
# server_name server_domain_or_ip
# Note:if there is only one server block, server name
# can be ommited, and all request will be process by
# can be omitted, and all request will be process by
# this only server
server_name 47.93.240.135;

Expand Down
116 changes: 116 additions & 0 deletions scripts/db_auto_backup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# -*- coding: UTF-8 -*-


"""本脚本用于定时备份mysql数据库
将mysqldump导出的数据存储到又拍云上。
每晚凌晨3点备份数据,Crontab命令如下:
0 3 * * * /bin/bash/python3 /path/to/file.py
"""


import hmac
import base64
import hashlib
import logging
import subprocess
from datetime import datetime
from requests import Session, Request

logging.basicConfig(filename="db_auto_backup.log", level=logging.DEBUG)


# 设置又拍云信息
# 注意: secret = hashlib.md5('操作员密码'.encode()).hexdigest()
OPERATOR_NAME = 'autobackup'
OPERATOR_SECRET = '51bfdb1f889e96484bf31eb74a82e804'
SERVICE_NAME = 'school-db-autobackup'
SERVER_URL = 'https://v0.api.upyun.com'

DB_USER = 'test'
DB_PASSWORD = 'Yq!((&1024'
DB_DATABASE = 'TEST'

class Upyun:
"""使用又拍云提供的REST API上传文件
文档地址:https://help.upyun.com/knowledge-base/rest_api/
认证方式采用签名认证:https://help.upyun.com/knowledge-base/object_storage_authorization/#e7adbee5908de8aea4e8af81
"""

@staticmethod
def _httpdate_rfc1123(dt=None):
dt = dt or datetime.utcnow()
return dt.strftime('%a, %d %b %Y %H:%M:%S GMT')

@staticmethod
def _sign(client_key, client_secret, method, uri, date, policy=None, md5=None):
"""签名"""
signarr = []
for v in [method, uri, date, policy, md5]:
if v is not None:
signarr.append(v)
signstr = '&'.join(signarr)
signstr = base64.b64encode(
hmac.new(client_secret.encode(), signstr.encode(),
digestmod=hashlib.sha1).digest()
).decode()
return 'UPYUN %s:%s' % (client_key, signstr)

@staticmethod
def _send_request(method, url, headers, body):
"""发送请求"""
s = Session()
prepped = Request(method, url).prepare()
prepped.headers = headers
prepped.body = body
r = s.send(prepped)
return r.status_code, r.text

@staticmethod
def upload(file_path, target_name, expire=None):
"""上传文件
:param file_path: 本地路径
:param target_name: 又拍云上的存储路径
:param expire: 过期时间(单位:天), 可选
:return: None
"""
with open(file_path, 'rb') as f:
file = f.read()
date = Upyun._httpdate_rfc1123()
file_md5 = hashlib.md5(file).hexdigest()
uri = '/{service}/{target}'.format(service=SERVICE_NAME, target=target_name)
method = 'PUT'
signature = Upyun._sign(OPERATOR_NAME, OPERATOR_SECRET, method, uri, date, md5=file_md5)
print(signature)
headers = {
'Authorization': signature,
'Date': date,
'Content-Length': str(len(file)),
'Content-MD5': file_md5,
}
if expire is not None:
headers['x-upyun-meta-ttl'] = expire

status, content = Upyun._send_request(method, SERVER_URL + uri, headers, file)

if status != 200:
raise Exception("Can't upload file via API, status=%d, response: %s" % (status, content))


def main():
backup_file_name = datetime.now().strftime('autobackup-%Y-%m-%d-%H:%M:%S.mysql-db.gz')
cmd = "mysqldump -u{user} -p{password} {db_name} | gzip > {output}".format(
user=DB_USER, password=DB_PASSWORD, db_name=DB_DATABASE, output=backup_file_name)
try:
subprocess.run(cmd, check=True)
Upyun.upload(backup_file_name, backup_file_name, 30)
except:
logging.exception("备份失败!")


if __name__ == '__main__':
main()
exit(0)
2 changes: 1 addition & 1 deletion test/upyun.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# 使用时需要根据自己配置与需求提供参数 key secret uri method
key = 'fondoger'
secret = '97eef486892c0b66f08a3228ebf676a3'
#secret = hashlib.md5('woshiwang2'.encode()).hexdigest()
#secret = hashlib.md5('操作员密码'.encode()).hexdigest()


def httpdate_rfc1123(dt=None):
Expand Down
7 changes: 0 additions & 7 deletions users_event.py

This file was deleted.

0 comments on commit 1005ee7

Please sign in to comment.