diff --git a/README.rst b/README.rst index aa2b447..d074428 100644 --- a/README.rst +++ b/README.rst @@ -61,7 +61,8 @@ file "Name": "MySQL Backup", "Command": "/home/bob/backups/backup-prep-script.sh", "Src": "/home/bob/backups/database/mysql_backup.sql", - "OutputPrefix": "main_db" + "OutputPrefix": "main_db", + "PreviousBackupsCount": 2 }, { "Name": "Websites Backup", @@ -74,6 +75,9 @@ file If emails are not required, then omit the ``EMAIL_FROM`` and ``EMAIL_TO`` fields of the configuration file. +If the ``PreviousBackupsCount`` is not set, then it will default to keeping +1 previous backup. It can be set to 0, which will only keep the current backup. + *Note*: When on Windows, it is better to pass the paths using forward slashes (/) as then escaping isn’t required (as with backslashes). The script will normalize the paths in these cases. However, when providing diff --git a/S3Backup/config_loader.py b/S3Backup/config_loader.py index 7d39100..38460cb 100644 --- a/S3Backup/config_loader.py +++ b/S3Backup/config_loader.py @@ -48,7 +48,6 @@ def config_setup(config_file): with open(config_file) as json_data_file: data = json.load(json_data_file) - print(data) failed = False @@ -64,8 +63,6 @@ def config_setup(config_file): if optional_value in data: configuration[optional_value] = data[optional_value] - print(configuration) - if failed: raise Exception('Missing keys from data. See log for details.') diff --git a/S3Backup/plan.py b/S3Backup/plan.py index e8b5da9..4efc583 100644 --- a/S3Backup/plan.py +++ b/S3Backup/plan.py @@ -32,7 +32,7 @@ from S3Backup import hash_file required_plan_values = ['Name', 'Src', 'OutputPrefix'] -optional_plan_values = ['Command'] +optional_plan_values = ['Command', 'PreviousBackupsCount'] logger = logging.getLogger(name='Plan') @@ -51,6 +51,13 @@ def __init__(self, raw_plan, configuration): self.name = raw_plan['Name'] self.src = raw_plan['Src'] self.command = None + + if 'PreviousBackupsCount' in raw_plan: + self.previous_backups_count = int(raw_plan['PreviousBackupsCount']) + else: + self.previous_backups_count = 1 + + self.output_file_prefix = raw_plan['OutputPrefix'] self.output_file = '%s_%s.zip' % (raw_plan['OutputPrefix'], time.strftime("%Y-%m-%d_%H-%M-%S")) self.new_hash = None @@ -69,6 +76,7 @@ def run(self): 3) Perform hash check to see if there are any changes (which would require an upload) 4) Upload destination file to S3 bucket 5) Update hash file with new hash + 6) Check if any previous backups need removing """ logger.info('Running plan "%s"', self.name) @@ -92,6 +100,9 @@ def run(self): updated = True + # 6) Remove any previous backups if required + self.__clear_old_backups() + finally: self.__cleanup() @@ -138,6 +149,40 @@ def __zip_files(self): logger.info('Output file created') + def __clear_old_backups(self): + try: + conn = boto.s3.connect_to_region( + self.CONFIGURATION['AWS_REGION'], + aws_access_key_id=self.CONFIGURATION['AWS_KEY'], + aws_secret_access_key=self.CONFIGURATION['AWS_SECRET']) + + bucket = conn.get_bucket(self.CONFIGURATION['AWS_BUCKET']) + + backup_keys = [] + + for key in bucket.list(prefix=self.output_file_prefix): + backup_keys.append(key.name) + + backup_keys.sort() + + logger.info('There are %d previous backups', len(backup_keys)) + + max_backups = self.previous_backups_count + 1 # Because this is run after current backup uploaded + + if len(backup_keys) > max_backups: + backups_to_remove = len(backup_keys) - max_backups + logger.info('Removing %d previous backups', backups_to_remove) + + for i in range(backups_to_remove): + logger.info('Removing previous backup: %s', backup_keys[i]) + bucket.delete_key(backup_keys[i]) + else: + logger.info('No previous backups require removal') + + except Exception, e: + logger.error('Failed to clear out previous backups from S3: %s', e) + raise + def __upload(self): try: conn = boto.s3.connect_to_region( diff --git a/config.json b/config.json index df27bec..c6222d1 100644 --- a/config.json +++ b/config.json @@ -11,7 +11,8 @@ "Name": "MySQL Backup", "Command": "mysqldump -u bob -p password > mysql_backup.sql", "Src": "c:/mysql_backup.sql", - "OutputPrefix": "main_db" + "OutputPrefix": "main_db", + "PreviousBackupsCount": 2 }, { "Name": "Website Backup",