<s> import argparse <EOL> import datetime <EOL> import logging <EOL> import os . path <EOL> import socket <EOL> from cassback import cassandra , dt_util <EOL> from cassback . subcommands import subcommands <EOL> class PurgeSubCommand ( subcommands . SubCommand ) : <EOL> """<STR_LIT>""" <EOL> log = logging . getLogger ( "<STR_LIT>" % ( __name__ , "<STR_LIT>" ) ) <EOL> command_name = "<STR_LIT>" <EOL> command_help = "<STR_LIT>" <EOL> command_description = "<STR_LIT>" <EOL> @ classmethod <EOL> def add_sub_parser ( cls , sub_parsers ) : <EOL> """<STR_LIT:U+0020>""" <EOL> sub_parser = super ( PurgeSubCommand , cls ) . add_sub_parser ( sub_parsers ) <EOL> sub_parser . add_argument ( "<STR_LIT>" , <EOL> default = socket . getfqdn ( ) , <EOL> help = "<STR_LIT>" ) <EOL> sub_parser . add_argument ( "<STR_LIT>" , dest = "<STR_LIT>" , default = False , <EOL> action = "<STR_LIT:store_true>" , <EOL> help = "<STR_LIT>" ) <EOL> purge_group = sub_parser . add_mutually_exclusive_group ( required = True ) <EOL> purge_group . add_argument ( "<STR_LIT>" , <EOL> dest = '<STR_LIT>' , <EOL> help = "<STR_LIT>" ) <EOL> purge_group . add_argument ( "<STR_LIT>" , <EOL> dest = '<STR_LIT>' , type = int , <EOL> help = "<STR_LIT>" ) <EOL> sub_parser . add_argument ( "<STR_LIT>" , <EOL> help = "<STR_LIT>" ) <EOL> return sub_parser <EOL> def __init__ ( self , args ) : <EOL> self . args = args <EOL> self . _validate_args ( ) <EOL> def _validate_args ( self ) : <EOL> if self . args . keep_days is not None and self . args . keep_days < <NUM_LIT:1> : <EOL> raise argparse . ArgumentError ( None , "<STR_LIT>" "<STR_LIT>" ) <EOL> return <EOL> def __call__ ( self ) : <EOL> """<STR_LIT>""" <EOL> endpoint = self . _endpoint ( self . args ) <EOL> purge_before = self . _calc_purge_before ( ) <EOL> manifest_days = self . _manifest_days ( purge_before ) <EOL> self . log . info ( "<STR_LIT>" "<STR_LIT>" , purge_before , manifest_days ) <EOL> self . log . debug ( "<STR_LIT>" , purge_before ) <EOL> manifests = [ ] <EOL> for manifest_day in manifest_days : <EOL> for manifest in self . _list_manifests ( endpoint , <EOL> self . args . keyspace , self . args . host , manifest_day ) : <EOL> if manifest . timestamp >= purge_before : <EOL> manifests . append ( manifest ) <EOL> else : <EOL> self . log . debug ( "<STR_LIT>" , manifest ) <EOL> self . log . info ( "<STR_LIT>" , manifests ) <EOL> keep_components = [ ] <EOL> for manifest in manifests : <EOL> keep_components . extend ( manifest . iter_components ( ) ) <EOL> self . log . info ( "<STR_LIT>" , keep_components ) <EOL> deleted_files = self . _purge_manifests ( endpoint , manifests ) <EOL> deleted_files . extend ( self . _purge_sstables ( endpoint , keep_components ) ) <EOL> str_build = [ "<STR_LIT>" . format ( <EOL> purge_before = dt_util . to_iso ( purge_before ) ) <EOL> ] <EOL> if self . args . dry_run : <EOL> str_build . append ( "<STR_LIT>" ) <EOL> else : <EOL> str_build . append ( "<STR_LIT>" ) <EOL> str_build . append ( "<STR_LIT>" ) <EOL> if deleted_files : <EOL> str_build . extend ( deleted_files ) <EOL> else : <EOL> str_build . append ( "<STR_LIT>" ) <EOL> return ( <NUM_LIT:0> , "<STR_LIT:\n>" . join ( str_build ) ) <EOL> def _manifest_days ( self , purge_before ) : <EOL> """<STR_LIT>""" <EOL> from_day = datetime . datetime ( purge_before . year , purge_before . month , <EOL> purge_before . day ) <EOL> now = dt_util . now ( ) <EOL> to_day = datetime . datetime ( now . year , now . month , now . day ) <EOL> assert from_day <= to_day <EOL> diff = to_day - from_day <EOL> return [ <EOL> from_day + datetime . timedelta ( d ) <EOL> for d in range ( diff . days + <NUM_LIT:1> ) <EOL> ] <EOL> def _calc_purge_before ( self ) : <EOL> """<STR_LIT>""" <EOL> if self . args . purge_before : <EOL> return dt_util . parse_date_input ( self . args . purge_before ) <EOL> assert ( self . args . keep_days or - <NUM_LIT:1> ) > <NUM_LIT:0> <EOL> return dt_util . now ( ) - datetime . timedelta ( self . args . keep_days ) <EOL> def _purge_manifests ( self , endpoint , keep_manifests ) : <EOL> """<STR_LIT>""" <EOL> keep_paths = frozenset ( <EOL> manifest . backup_path <EOL> for manifest in keep_manifests <EOL> ) <EOL> self . log . debug ( "<STR_LIT>" . format ( <EOL> keep_paths = keep_paths ) ) <EOL> keyspace_dir = cassandra . KeyspaceBackup . backup_keyspace_dir ( <EOL> self . args . keyspace ) <EOL> deleted = [ ] <EOL> for manifest_path in endpoint . iter_dir ( keyspace_dir , recursive = True ) : <EOL> if manifest_path in keep_paths : <EOL> self . log . debug ( "<STR_LIT>" , manifest_path ) <EOL> else : <EOL> self . log . debug ( "<STR_LIT>" , manifest_path ) <EOL> deleted . append ( endpoint . remove_file ( manifest_path , <EOL> dry_run = self . args . dry_run ) ) <EOL> return deleted <EOL> def _purge_sstables ( self , endpoint , kept_components ) : <EOL> """<STR_LIT>""" <EOL> ks_dir = cassandra . BackupFile . backup_keyspace_dir ( self . args . host , <EOL> self . args . keyspace ) <EOL> set_kept_files = frozenset ( <EOL> component . backup_file_name <EOL> for component in kept_components <EOL> ) <EOL> deleted_files = [ ] <EOL> for file_path in endpoint . iter_dir ( ks_dir , recursive = True ) : <EOL> _ , file_name = os . path . split ( file_path ) <EOL> if file_name in set_kept_files : <EOL> self . log . debug ( "<STR_LIT>" , file_path ) <EOL> else : <EOL> self . log . debug ( "<STR_LIT>" , file_path ) <EOL> deleted_files . append ( endpoint . remove_file_with_meta ( <EOL> file_path , dry_run = self . args . dry_run ) ) <EOL> return deleted_files </s>
