def get_credentials(): from google_auth_oauthlib.flow import InstalledAppFlow SCOPES = ['https://www.googleapis.com/auth/drive.file'] client_config = { "installed": { "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://accounts.google.com/o/oauth2/token", "redirect_uris": ["urn:ietf:wg:oauth:2.0:oob", "http://localhost"], "client_id": get_ecredentials('yatch'), "client_secret": get_ecredentials('bakery') } } flow = InstalledAppFlow.from_client_config(client_config, SCOPES) print('\n') try: credentials = flow.run_console( authorization_prompt_message='Please visit the below URL to get ' 'autorization\ncode to authorize Google Drive access\n\n{url}', authorization_code_message='\nAuthorization Code\n' ) client_config['installed']['refresh_token'] = credentials.refresh_token client_config['installed'].pop('client_id') client_config['installed'].pop('client_secret') backup_options['oauth'] = client_config['installed'] except Exception as e: error_and_exit( '\nAn Error occured while authenticating Gdrive access\n{0}'.format(e)) return credentials
def setup_gdrive(): credentials = get_credentials() display_msg('\nPlease wait till the Gdrive setup is complete..', 'bold') from apiclient.discovery import build from apiclient.http import MediaFileUpload drive = build('drive', 'v3', credentials=credentials) file_id = create_backup_folder(drive) if file_id is not None: file_metadata = { 'name': 'backup.tar.gz', 'parents': [file_id], 'mimeType': 'application/gzip' } status = execute_command( "echo 'This text file is the initial backup' > backup.txt && " "tar -czvf backup.tar.gz backup.txt" ) if status.returncode == 0: media = MediaFileUpload('backup.tar.gz') resp = drive.files().create(body=file_metadata, media_body=media, fields='id').execute() backup_options['backup_file_id'] = resp.get('id') execute_command('rm backup.txt backup.tar.gz') display_msg('Google Drive configured successfully', 'options') else: error_and_exit('\nInitial file creation failed') else: error_and_exit('\nAn Error occured while creating folder on Gdrive')
def setup_cron(): from crontab import CronTab try: username = execute_command("whoami").stdout.strip() username = str(username, 'utf-8') cron = CronTab(user=username) except Exception as e: error_and_exit('\n{0}\n' 'An Error occured while scheduling backup task'.format(e)) script_command = 'python3 /opt/ghost-backup/backup.py > /opt/ghost-backup/backup.log 2>&1' jobs = cron.find_command(script_command) for job in jobs: if job.command == script_command: backup_options['cron_written'] = True break if not backup_options.get('cron_written', False): job = cron.new( command=script_command, comment='Ghost blog daily backup' ) job.hour.on(0) job.minute.on(0) cron.write() backup_options['cron_written'] = True
def create_backup_folder(drive): folder_query = ('mimeType="application/vnd.google-apps.folder" and ' 'name = "Ghost Backup" and trashed = False') try: resp = drive.files().list(q=folder_query).execute() except Exception as e: error_and_exit( '\n{0}\nAn Error occured while hitting request to Gdrive'.format(e)) use_existing_folder = False if len(resp.get('files')) > 0: use_existing_folder = display_yn_prompt("Ghost Backup folder found " "on your Google Drive.\nDo you want to use it as your backup folder?\n" "(No will create a new folder with the same name)", '', 'Y', False) if use_existing_folder: resp = resp['files'][0] display_msg('Using existing folder', 'bold') else: file_metadata = { 'name': 'Ghost Backup', 'mimeType': 'application/vnd.google-apps.folder' } resp = drive.files().create(body=file_metadata, fields='id').execute() return resp.get('id')
def pack_files(): compress_command = 'tar -C {0} -cvzf {1}-{2}.tar.gz {2}.sql'.format( config['dump_path'], config['app_name'], config['timestamp']) if config['images']: compress_command += ' images' if config['themes']: compress_command += ' themes' status = execute_command(compress_command) if status.returncode != 0: print("state code here %s " % status.returncode) error_and_exit( '\nError while packing backup files\n\n{0}'.format( format_subprocess_error(status)), config.get('telegram_user_id'))
def dump_db(): if config['images'] and config['themes']: dump_path = config['images_dir'] if config['images'] else config[ 'themes_dir'] config['dump_path'] = os.path.normpath(dump_path + '/..') else: config['dump_path'] = os.getcwd() config['dump_file'] = config['dump_path'] + '/{0}.sql'.format( config['timestamp']) dump_command = ("mysqldump -h{mysql_hostname} -u'{mysql_username}' " "-p'{mysql_password}' {mysql_db_name} > {0}".format( config['dump_file'], **config)) status = execute_command(dump_command) if status.returncode != 0: print("state code here %s " % status.returncode) error_and_exit( '\nError while taking DB dump\n\n{0}'.format( format_subprocess_error(status)), config.get('telegram_user_id'))
display_yn_prompt("\nWould you like to backup images?", 'images') display_yn_prompt("\nWould you like to backup themes?", 'themes') display_input_prompt('\nApp name') display_input_prompt('\nMySQL hostname', 'localhost') display_input_prompt('\nMySQL username', 'root') display_input_prompt('\nMySQL password') display_input_prompt('\nMySQL DB name') setup_gdrive() copy_files() setup_cron() display_yn_prompt("Would you like to get notifications\n" "on Telegram about backup status?", 'notification', 'Y') if backup_options['notification']: setup_notifications() write_config() display_msg('\nBackup setup completed succesfully!!!\n', 'options') if __name__ == '__main__': try: main() except Exception as e: error_and_exit("\nFollowing error occured:\n{0}\n\n" "More info about the error:\n{1}".format(e, format_exc()))
resp = drive.files().update(body=file_metadata, fileId=config['backup_file_id'], media_body=media).execute() def delete_backups(): execute_command('rm {0} {1}.tar.gz'.format(config['dump_file'], config['timestamp'])) def main(): read_config() dump_db() pack_files() upload_files() delete_backups() send_notif( config.get('telegram_user_id'), 'Backup completed successfully for ' + config.get('app_name') + '.com' + '!') if __name__ == '__main__': try: main() except Exception as e: error_and_exit( "\nFollowing error occured:\n{0}\n\n" "More info about the error:\n{1}".format(e, format_exc()), config.get('telegram_user_id'))