def delete_with_retention(self, num_to_retain):
        """
        Retain the num_to_retain most recent backups and delete all data
        before them.

        """
        base_backup_sentinel_depth = self.layout.basebackups().count('/') + 1

        # Sweep over base backup files, collecting sentinel files from
        # completed backups.
        completed_basebackups = []
        for key in self._backup_list(prefix=self.layout.basebackups()):

            key_name = self.layout.key_name(key)
            key_parts = key_name.split('/')
            key_depth = len(key_parts)
            url = '{scheme}://{bucket}/{name}'.format(
                scheme=self.layout.scheme,
                bucket=self._container_name(key),
                name=key_name)

            if key_depth == base_backup_sentinel_depth:
                # This is a key at the depth of a base-backup-sentinel file.
                # Check to see if it matches the known form.
                match = re.match(storage.COMPLETE_BASE_BACKUP_REGEXP,
                                 key_parts[-1])

                # If this isn't a base-backup-sentinel file, just ignore it.
                if match is None:
                    continue

                # This key corresponds to a base-backup-sentinel file and
                # represents a completed backup. Grab its segment number.
                scanned_sn = \
                    self._groupdict_to_segment_number(match.groupdict())
                completed_basebackups.append(dict(
                    scanned_sn=scanned_sn,
                    url=url))

        # Sort the base backups from newest to oldest.
        basebackups = sorted(
                        completed_basebackups,
                        key=lambda backup: backup['scanned_sn'].as_an_integer,
                        reverse=True)
        last_retained = None
        if len(basebackups) <= num_to_retain:
            detail = None
            if len(basebackups) == 0:
                msg = 'Not deleting any data.'
                detail = 'No existing base backups.'
            elif len(basebackups) == 1:
                last_retained = basebackups[-1]
                msg = 'Retaining existing base backup.'
            else:
                last_retained = basebackups[-1]
                msg = "Retaining all %d base backups." % len(basebackups)
        else:
            last_retained = basebackups[num_to_retain - 1]
            num_deleting = len(basebackups) - num_to_retain
            msg = "Deleting %d oldest base backups." % num_deleting
            detail = "Found %d total base backups." % len(basebackups)
        log_message = dict(msg=msg)
        if detail is not None:
            log_message['detail'] = detail
        if last_retained is not None:
            log_message['hint'] = \
                "Deleting keys older than %s." % last_retained['url']
        logger.info(**log_message)

        # This will delete all base backup and WAL data before
        # last_retained['scanned_sn'].
        if last_retained is not None:
            self._delete_base_backups_before(last_retained['scanned_sn'])
            self._delete_wals_before(last_retained['scanned_sn'])

        if self.deleter:
            self.deleter.close()
def delete_with_retention ( self , num_to_retain ) : base_backup_sentinel_depth = self . layout . basebackups ( ) . count ( '/' ) + 1 completed_basebackups = [ ] for key in self . _backup_list ( prefix = self . layout . basebackups ( ) ) : key_name = self . layout . key_name ( key ) key_parts = key_name . split ( '/' ) key_depth = len ( key_parts ) url = '{scheme}://{bucket}/{name}' . format ( scheme = self . layout . scheme , bucket = self . _container_name ( key ) , name = key_name ) if key_depth == base_backup_sentinel_depth : match = re . match ( storage . COMPLETE_BASE_BACKUP_REGEXP , key_parts [ - 1 ] ) if match is None : continue scanned_sn = self . _groupdict_to_segment_number ( match . groupdict ( ) ) completed_basebackups . append ( dict ( scanned_sn = scanned_sn , url = url ) ) basebackups = sorted ( completed_basebackups , key = lambda backup : backup [ 'scanned_sn' ] . as_an_integer , reverse = True ) last_retained = None if len ( basebackups ) <= num_to_retain : detail = None if len ( basebackups ) == 0 : msg = 'Not deleting any data.' detail = 'No existing base backups.' elif len ( basebackups ) == 1 : last_retained = basebackups [ - 1 ] msg = 'Retaining existing base backup.' else : last_retained = basebackups [ - 1 ] msg = "Retaining all %d base backups." % len ( basebackups ) else : last_retained = basebackups [ num_to_retain - 1 ] num_deleting = len ( basebackups ) - num_to_retain msg = "Deleting %d oldest base backups." % num_deleting detail = "Found %d total base backups." % len ( basebackups ) log_message = dict ( msg = msg ) if detail is not None : log_message [ 'detail' ] = detail if last_retained is not None : log_message [ 'hint' ] = "Deleting keys older than %s." % last_retained [ 'url' ] logger . info ( ** log_message ) if last_retained is not None : self . _delete_base_backups_before ( last_retained [ 'scanned_sn' ] ) self . _delete_wals_before ( last_retained [ 'scanned_sn' ] ) if self . deleter : self . deleter . close ( )
Retain the num_to_retain most recent backups and delete all data
        before them.