2020-03-26 18:58:50 +00:00
import os
import datetime
2020-06-25 17:53:31 +00:00
import json
2020-03-26 18:58:50 +00:00
import tarfile
import hashlib
import frappe
import boto3
2020-04-16 06:19:40 +00:00
from new import get_password
2020-03-26 18:58:50 +00:00
from push_backup import DATE_FORMAT , check_environment_variables
from frappe . utils import get_sites , random_string
2020-06-25 17:53:31 +00:00
from frappe . installer import make_conf , get_conf_params , make_site_dirs , update_site_config
2020-03-26 18:58:50 +00:00
from check_connection import get_site_config , get_config
2020-04-28 20:15:59 +00:00
2020-03-26 18:58:50 +00:00
def list_directories ( path ) :
directories = [ ]
for name in os . listdir ( path ) :
if os . path . isdir ( os . path . join ( path , name ) ) :
directories . append ( name )
return directories
2020-04-28 20:15:59 +00:00
2020-03-26 18:58:50 +00:00
def get_backup_dir ( ) :
return os . path . join (
os . path . expanduser ( ' ~ ' ) ,
' backups '
)
2020-04-28 20:15:59 +00:00
2020-03-26 18:58:50 +00:00
def decompress_db ( files_base , site ) :
database_file = files_base + ' -database.sql.gz '
command = ' gunzip -c {database_file} > {database_extract} ' . format (
database_file = database_file ,
2020-04-28 20:15:59 +00:00
database_extract = database_file . replace ( ' .gz ' , ' ' )
2020-03-26 18:58:50 +00:00
)
print ( ' Extract Database GZip for site {} ' . format ( site ) )
os . system ( command )
2020-04-28 20:15:59 +00:00
2020-06-25 17:53:31 +00:00
def restore_database ( files_base , site_config_path , site ) :
2020-04-16 06:19:40 +00:00
db_root_password = get_password ( ' MYSQL_ROOT_PASSWORD ' )
2020-03-26 18:58:50 +00:00
if not db_root_password :
print ( ' Variable MYSQL_ROOT_PASSWORD not set ' )
exit ( 1 )
db_root_user = os . environ . get ( " DB_ROOT_USER " , ' root ' )
2020-03-27 10:37:12 +00:00
# restore database
2020-03-26 18:58:50 +00:00
database_file = files_base + ' -database.sql.gz '
decompress_db ( files_base , site )
config = get_config ( )
site_config = get_site_config ( site )
# mysql command prefix
mysql_command = ' mysql -u {db_root_user} -h {db_host} -p {db_password} -e ' . format (
db_root_user = db_root_user ,
db_host = config . get ( ' db_host ' ) ,
db_password = db_root_password
)
2020-03-27 10:37:12 +00:00
# drop db if exists for clean restore
2020-04-29 06:14:58 +00:00
drop_database = mysql_command + " \" DROP DATABASE IF EXISTS \ ` {db_name} \ `; \" " . format (
2020-03-27 10:37:12 +00:00
db_name = site_config . get ( ' db_name ' )
)
os . system ( drop_database )
2020-03-26 18:58:50 +00:00
# create db
2020-04-29 06:14:58 +00:00
create_database = mysql_command + " \" CREATE DATABASE IF NOT EXISTS \ ` {db_name} \ `; \" " . format (
2020-03-26 18:58:50 +00:00
db_name = site_config . get ( ' db_name ' )
)
os . system ( create_database )
# create user
create_user = mysql_command + " \" CREATE USER IF NOT EXISTS \' {db_name} \' @ \' % \' IDENTIFIED BY \' {db_password} \' ; FLUSH PRIVILEGES; \" " . format (
db_name = site_config . get ( ' db_name ' ) ,
db_password = site_config . get ( ' db_password ' )
)
os . system ( create_user )
2020-04-29 17:22:15 +00:00
# grant db privileges to user
grant_privileges = mysql_command + " \" GRANT ALL PRIVILEGES ON \ ` {db_name} \ `.* TO ' {db_name} ' @ ' % ' IDENTIFIED BY ' {db_password} ' ; FLUSH PRIVILEGES; \" " . format (
2020-03-27 10:37:12 +00:00
db_name = site_config . get ( ' db_name ' ) ,
db_password = site_config . get ( ' db_password ' )
)
2020-03-26 18:58:50 +00:00
os . system ( grant_privileges )
command = " mysql -u {db_root_user} -h {db_host} -p {db_password} ' {db_name} ' < {database_file} " . format (
db_root_user = db_root_user ,
db_host = config . get ( ' db_host ' ) ,
db_password = db_root_password ,
db_name = site_config . get ( ' db_name ' ) ,
2020-04-28 20:15:59 +00:00
database_file = database_file . replace ( ' .gz ' , ' ' ) ,
2020-03-26 18:58:50 +00:00
)
print ( ' Restoring database for site: {} ' . format ( site ) )
os . system ( command )
2020-06-25 17:53:31 +00:00
if os . path . exists ( site_config_path ) :
with open ( site_config_path , ' r ' ) as sc :
site_config = json . load ( sc )
encryption_key = site_config . get ( " encryption_key " )
if encryption_key :
print ( ' Restoring site config for site: {} ' . format ( site ) )
update_site_config ( ' encryption_key ' , encryption_key ,
site_config_path = os . path . join ( os . getcwd ( ) , site , " site_config.json " ) )
2020-04-28 20:15:59 +00:00
2020-03-26 18:58:50 +00:00
def restore_files ( files_base ) :
public_files = files_base + ' -files.tar '
# extract tar
public_tar = tarfile . open ( public_files )
print ( ' Extracting {} ' . format ( public_files ) )
public_tar . extractall ( )
2020-04-28 20:15:59 +00:00
2020-03-26 18:58:50 +00:00
def restore_private_files ( files_base ) :
private_files = files_base + ' -private-files.tar '
private_tar = tarfile . open ( private_files )
print ( ' Extracting {} ' . format ( private_files ) )
private_tar . extractall ( )
2020-04-28 20:15:59 +00:00
2020-03-26 18:58:50 +00:00
def pull_backup_from_s3 ( ) :
check_environment_variables ( )
# https://stackoverflow.com/a/54672690
s3 = boto3 . resource (
' s3 ' ,
2020-04-26 17:18:35 +00:00
region_name = os . environ . get ( ' REGION ' ) ,
2020-03-26 18:58:50 +00:00
aws_access_key_id = os . environ . get ( ' ACCESS_KEY_ID ' ) ,
aws_secret_access_key = os . environ . get ( ' SECRET_ACCESS_KEY ' ) ,
endpoint_url = os . environ . get ( ' ENDPOINT_URL ' )
)
bucket_dir = os . environ . get ( ' BUCKET_DIR ' )
bucket_name = os . environ . get ( ' BUCKET_NAME ' )
bucket = s3 . Bucket ( bucket_name )
# Change directory to /home/frappe/backups
os . chdir ( get_backup_dir ( ) )
2020-05-22 09:45:33 +00:00
backup_files = [ ]
sites = set ( )
site_timestamps = set ( )
download_backups = [ ]
2020-04-28 20:15:59 +00:00
for obj in bucket . objects . filter ( Prefix = bucket_dir ) :
backup_file = obj . key . replace ( os . path . join ( bucket_dir , ' ' ) , ' ' )
2020-05-22 09:45:33 +00:00
backup_files . append ( backup_file )
site_name , timestamp , backup_type = backup_file . split ( ' / ' )
site_timestamp = site_name + ' / ' + timestamp
sites . add ( site_name )
site_timestamps . add ( site_timestamp )
# sort sites for latest backups
for site in sites :
backup_timestamps = [ ]
for site_timestamp in site_timestamps :
site_name , timestamp = site_timestamp . split ( ' / ' )
if site == site_name :
timestamp_datetime = datetime . datetime . strptime (
timestamp , DATE_FORMAT
)
backup_timestamps . append ( timestamp )
download_backups . append ( site + ' / ' + max ( backup_timestamps ) )
# Only download latest backups
for backup_file in backup_files :
for backup in download_backups :
if backup in backup_file :
if not os . path . exists ( os . path . dirname ( backup_file ) ) :
os . makedirs ( os . path . dirname ( backup_file ) )
print ( ' Downloading {} ' . format ( backup_file ) )
bucket . download_file ( bucket_dir + ' / ' + backup_file , backup_file )
2020-03-26 18:58:50 +00:00
os . chdir ( os . path . join ( os . path . expanduser ( ' ~ ' ) , ' frappe-bench ' , ' sites ' ) )
2020-04-28 20:15:59 +00:00
2020-03-26 18:58:50 +00:00
def main ( ) :
backup_dir = get_backup_dir ( )
if len ( list_directories ( backup_dir ) ) == 0 :
pull_backup_from_s3 ( )
for site in list_directories ( backup_dir ) :
2020-04-28 20:15:59 +00:00
site_slug = site . replace ( ' . ' , ' _ ' )
backups = [ datetime . datetime . strptime ( backup , DATE_FORMAT ) for backup in list_directories ( os . path . join ( backup_dir , site ) ) ]
2020-03-26 18:58:50 +00:00
latest_backup = max ( backups ) . strftime ( DATE_FORMAT )
files_base = os . path . join ( backup_dir , site , latest_backup , ' ' )
files_base + = latest_backup + ' - ' + site_slug
2020-06-25 17:53:31 +00:00
site_config_path = os . path . join ( backup_dir , site , ' site_config.json ' )
2020-03-26 18:58:50 +00:00
if site in get_sites ( ) :
2020-06-25 17:53:31 +00:00
restore_database ( files_base , site_config_path , site )
2020-03-26 18:58:50 +00:00
restore_private_files ( files_base )
restore_files ( files_base )
else :
2020-04-16 06:19:40 +00:00
mariadb_root_password = get_password ( ' MYSQL_ROOT_PASSWORD ' )
2020-03-26 18:58:50 +00:00
if not mariadb_root_password :
print ( ' Variable MYSQL_ROOT_PASSWORD not set ' )
exit ( 1 )
site_config = get_conf_params (
db_name = ' _ ' + hashlib . sha1 ( site . encode ( ) ) . hexdigest ( ) [ : 16 ] ,
db_password = random_string ( 16 )
)
frappe . local . site = site
frappe . local . sites_path = os . getcwd ( )
frappe . local . site_path = os . getcwd ( ) + ' / ' + site
make_conf (
db_name = site_config . get ( ' db_name ' ) ,
2020-03-27 10:37:12 +00:00
db_password = site_config . get ( ' db_password ' ) ,
2020-03-26 18:58:50 +00:00
)
2020-03-27 10:37:12 +00:00
make_site_dirs ( )
2020-03-26 18:58:50 +00:00
restore_database ( files_base , site )
restore_private_files ( files_base )
restore_files ( files_base )
exit ( 0 )
2020-04-28 20:15:59 +00:00
2020-03-26 18:58:50 +00:00
if __name__ == " __main__ " :
main ( )