GitLab saves files with the pattern 1530410429_2018_07_01_11.0.1_gitlab_backup.tar
(epoch, date, version, fixed string) to an S3 container.
I wanted to create a Python module to manage those backups, particularly to delete old backups, but preserving a specified number of files for each version).
To this end I:
- read S3 bucket contents and populate a list of dictionaries containing file name and an extracted version
- extract a set of versions from the above list
- iterate over each version and create a list of files to delete
- iterate over the above result and delete the files from the bucket
It works, but I feel the data structures I used are not appropriate and not pythonic.
How could I simplify the data structures and possibly minimize the number of function calls.
import boto3
def get_set_of_versions(table_of_backups):
set_of_versions = set()
for backup in table_of_backups:
set_of_versions.add(backup['gitlab_version'])
return set_of_versions
def create_table_of_backups(list_of_backup_files):
table_of_backups = [
{
"s3_object_name": filename,
"gitlab_version": filename.split('_')[4]
} for filename in list_of_backup_files
]
return table_of_backups
def extract_list_of_backups(list_of_objects):
list_of_backups = [s3_object.key for s3_object in list_of_objects if 'gitlab_backup' in s3_object.key]
return list_of_backups
class GitlabBackups:
def __init__(self, bucket_name):
self.bucket_name = bucket_name
self.s3 = boto3.resource('s3')
self.bucket = self.s3.Bucket(bucket_name)
self.list_of_backup_files = extract_list_of_backups(self.bucket.objects.all())
self.table_of_backups = create_table_of_backups(self.list_of_backup_files)
self.set_of_versions = get_set_of_versions(self.table_of_backups)
def return_candidates_for_deletion_within_version(self, version, generations_to_keep=1):
if generations_to_keep == 0:
raise ValueError
list_of_versioned_backups = [
backup for backup in self.table_of_backups if backup['gitlab_version'] == version
]
return [backup['s3_object_name'] for backup in list_of_versioned_backups[:-generations_to_keep]]
def return_candidates_for_deletion(self, generations_to_keep=2):
resulting_list = list()
for version in self.set_of_versions:
resulting_list.extend(self.return_candidates_for_deletion_within_version(version, generations_to_keep))
return resulting_list
def delete_old_backups(self, generations_to_keep=2):
list_to_delete = self.return_candidates_for_deletion(generations_to_keep)
for key in list_to_delete:
self.s3.Object(self.bucket_name, key).delete()