#!/usr/bin/env python3 # # ex:ts=4:sw=4:sts=4:et # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- # # Security Response Tool Commandline Tool # # Copyright (C) 2018-2019 Wind River Systems # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ### Usage Examples (run from top level directory) # ./bin/srtool_utils.py -b # back up to 'week_year' dir the database file, data files, attachments # ./bin/srtool_utils.py -d # back up to 'weekday' dir the database file, data files, attachments import os import sys import argparse import sqlite3 import json from datetime import datetime, date # load the srt.sqlite schema indexes dir_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) sys.path.insert(0, dir_path) from common.srt_schema import ORM # Setup: verbose = False srtDbName = 'srt.sqlite' BACKUP_DIR = 'backups' BACKUP_PREFIX = 'backup_' ################################# # Common routines # # quick development/debugging support def _log(msg): DBG_LVL = os.environ['SRTDBG_LVL'] if ('SRTDBG_LVL' in os.environ) else 2 DBG_LOG = os.environ['SRTDBG_LOG'] if ('SRTDBG_LOG' in os.environ) else '/tmp/srt_dbg.log' if 1 == DBG_LVL: print(msg) elif 2 == DBG_LVL: f1=open(DBG_LOG, 'a') f1.write("|" + msg + "|\n" ) f1.close() ################################# # Set backup database stamp file # def backup_stamp(backup_dir): if not os.path.isdir(backup_dir): print("ERROR: no such directory '%s'" % backup_dir) exit(1) statinfo = os.stat(os.path.join(backup_dir, 'srt.sqlite')) mod_timestamp = datetime.fromtimestamp(statinfo.st_mtime) stamp_str = mod_timestamp.strftime('%Y-%m-%d %H:%M:%S | %A, %B %d %Y') with open(os.path.join(backup_dir,'timestamp.txt'), 'w') as file: file.write('%s\n' % stamp_str) print("* Set Timestamp:%s" % mod_timestamp.strftime('%Y-%m-%d|%H:%M:%S|%A, %B %d %Y')) ################################# # Backup the database and data files # def backup_db(is_daily): today = datetime.today() weeknum = today.strftime("%W") weekday = today.strftime("%A") #today.isoweekday() year = today.strftime("%Y") # Where are we backing up to if is_daily: backup_dir = os.path.join(script_pathname, "%s/%s%s" % (BACKUP_DIR,BACKUP_PREFIX,weekday)) else: backup_dir = os.path.join(script_pathname, "%s/%s%s_%s" % (BACKUP_DIR,BACKUP_PREFIX,year,weeknum)) # Make sure directory exists try: os.makedirs(backup_dir) except: # If exists, clean it out os.system("rm -rf %s/*" % (backup_dir)) pass os.makedirs(os.path.join(backup_dir,'data')) print("*** Backup dir='%s' ***" % backup_dir) print("* Copy database") cmd = 'cp -p %s %s' % (os.path.join(script_pathname,srtDbName),backup_dir) print(cmd) os.system(cmd) # Copy data but skip cache dir (no deep copy) print("* Copy data files") cmd = 'cp -p %s/data/* %s/data' % (script_pathname,backup_dir) print(cmd) os.system(cmd) # Copy attachments print("* Copy attachment files") cmd = 'cp -r -p %s/downloads %s' % (script_pathname,backup_dir) print(cmd) os.system(cmd) # Set stamp file backup_stamp(backup_dir) ####################################################################### # list # def backup_list(): def sort_key(elem): return elem[0]+elem[2] stamps = [] for directory in os.listdir(os.path.join(script_pathname, 'backups')): prefix = '1Week' if not directory[len(BACKUP_PREFIX)].isalpha() else '2Day' directory = os.path.join(script_pathname, 'backups', directory) with open(os.path.join(directory,'timestamp.txt'), 'r') as file: line = file.read().strip() #print("DIR=%s,%s" % (directory,line)) stamps.append([prefix, directory, line]) # Add the current database (now) prefix = '3Now' directory = script_pathname statinfo = os.stat(os.path.join(directory, 'srt.sqlite')) mod_timestamp = datetime.fromtimestamp(statinfo.st_mtime) stamp_str = mod_timestamp.strftime('%Y-%m-%d %H:%M:%S | %A, %B %d %Y') stamps.append([prefix, directory, stamp_str]) # Sort my time and return stamps.sort(key=sort_key) return stamps def list(db_list=False): stamps = backup_list() for stamp in stamps: # Insert a separator between the date and the time stamp[2] = stamp[2].replace(' ','|',1) if db_list: print("%s|%s|%s" % (stamp[0][1:],os.path.basename(stamp[1]),stamp[2].replace(' | ','|'))) else: snap_date,snap_time,snap_day = stamp[2].split('|') print("%-4s,%-16s,%s" % (stamp[0][1:],os.path.basename(stamp[1]),stamp[2].replace(' | ','|'))) ################################# # Init stamps # def init_stamps(): stamps = backup_list() for stamp in stamps: stamp_prefix, stamp_directory, stamp_line = stamp backup_stamp(stamp_directory) ################################# # main loop # def main(argv): global verbose global cmd_skip global cmd_count # setup parser = argparse.ArgumentParser(description='srtool_backup.py: backup the SRTool database') parser.add_argument('--backup-db', '-b', action='store_const', const='backup', dest='command', help='Backup the database, save to year_weeknum dir') parser.add_argument('--backup-db-daily', '-d', action='store_const', const='backup-daily', dest='command', help='Backup the database, save to weekday dir') parser.add_argument('--init-stamps', '-I', action='store_const', const='init-stamps', dest='command', help='Initialize the backup directory timestamps') parser.add_argument('--init-dir-stamp', '-D', dest='init_dir_stamp', help='Initialize a specific backup directory timestamp') parser.add_argument('--list-backups', '-l', action='store_const', const='list', dest='command', help='List the backup directory timestamps') parser.add_argument('--list-backups-db', '-L', action='store_const', const='list-db', dest='command', help='Dump the backup directory timestamps') parser.add_argument('--force', '-f', action='store_true', dest='force', help='Force the update') parser.add_argument('--update-skip-history', '-H', action='store_true', dest='update_skip_history', help='Skip history updates') parser.add_argument('--verbose', '-v', action='store_true', dest='verbose', help='Debugging: verbose output') parser.add_argument('--skip', dest='skip', help='Debugging: skip record count') parser.add_argument('--count', dest='count', help='Debugging: short run record count') args = parser.parse_args() master_log = open(os.path.join(script_pathname, "update_logs/master_log.txt"), "a") verbose = args.verbose cmd_skip = 0 if None != args.skip: cmd_skip = int(args.skip) cmd_count = 0 if None != args.count: cmd_count = int(args.count) if ('backup' == args.command) or ('backup-daily' == args.command): try: backup_db('backup-daily' == args.command) master_log.write("SRTOOL:%s:DATABASE BACKUP:\t\t\t\t...\t\t\tSUCCESS\n" % date.today()) print ("DATABASE BACKUP SUCCESSFUL\n") except Exception as e: print ("DATABASE BACKUP FAILED ... %s" % e) master_log.write("SRTOOL:%s:DATABASE BACKUP:\t\t\t\t...\t\t\tFAILED ... %s\n" % (date.today(), e)) elif 'list' == args.command: list() elif 'list-db' == args.command: list(True) elif 'init-stamps' == args.command: init_stamps() elif args.command.init_dir_stamp: backup_stamp(args.command.init_dir_stamp) else: print("Command not found") master_log.close() if __name__ == '__main__': script_pathname = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))) main(sys.argv[1:])