-
Notifications
You must be signed in to change notification settings - Fork 392
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/ timeline id in clone section for Spilo #760
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -20,25 +20,45 @@ | |||||||
|
||||||||
def read_configuration(): | ||||||||
parser = argparse.ArgumentParser(description="Script to clone from S3 with support for point-in-time-recovery") | ||||||||
parser.add_argument('--scope', required=True, help='target cluster name') | ||||||||
parser.add_argument('--datadir', required=True, help='target cluster postgres data directory') | ||||||||
parser.add_argument('--scope', required=True, | ||||||||
help='target cluster name') | ||||||||
parser.add_argument('--datadir', required=True, | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
help='target cluster postgres data directory') | ||||||||
parser.add_argument('--recovery-target-time', | ||||||||
help='the timestamp up to which recovery will proceed (including time zone)', | ||||||||
dest='recovery_target_time_string') | ||||||||
parser.add_argument('--dry-run', action='store_true', help='find a matching backup and build the wal-e ' | ||||||||
parser.add_argument('--dry-run', action='store_true', | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
help='find a matching backup and build the wal-e ' | ||||||||
'command to fetch that backup without running it') | ||||||||
parser.add_argument('--recovery-target-timeline', | ||||||||
help='the timeline up to which recovery will proceed. Leave empty for latest.', | ||||||||
dest='recovery_target_timeline', | ||||||||
type=lambda timeline_id: int(timeline_id,16)) | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
args = parser.parse_args() | ||||||||
|
||||||||
options = namedtuple('Options', 'name datadir recovery_target_time dry_run') | ||||||||
options = namedtuple('Options', 'name datadir recovery_target_time recovery_target_timeline dry_run') | ||||||||
if args.recovery_target_time_string: | ||||||||
recovery_target_time = parse(args.recovery_target_time_string) | ||||||||
if recovery_target_time.tzinfo is None: | ||||||||
raise Exception("recovery target time must contain a timezone") | ||||||||
else: | ||||||||
recovery_target_time = None | ||||||||
|
||||||||
return options(args.scope, args.datadir, recovery_target_time, args.dry_run) | ||||||||
if args.recovery_target_timeline == None: | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
recovery_target_timeline = get_latest_timeline() | ||||||||
else: | ||||||||
recovery_target_timeline = args.recovery_target_timeline | ||||||||
|
||||||||
return options(args.scope, args.datadir, recovery_target_time, recovery_target_timeline, args.dry_run) | ||||||||
|
||||||||
def get_latest_timeline(): | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
env = os.environ.copy() | ||||||||
backup_list = list_backups(env) | ||||||||
latest_timeline_id = int("00000000",16) | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
for backup in backup_list: | ||||||||
if int(backup["name"][5:13], 16) > latest_timeline_id: | ||||||||
latest_timeline_id = int(backup["name"][5:13], 16) | ||||||||
return latest_timeline_id | ||||||||
|
||||||||
def build_wale_command(command, datadir=None, backup=None): | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
cmd = ['wal-g' if os.getenv('USE_WALG_RESTORE') == 'true' else 'wal-e'] + [command] | ||||||||
|
@@ -65,16 +85,18 @@ def fix_output(output): | |||||||
yield '\t'.join(line.split()) | ||||||||
|
||||||||
|
||||||||
def choose_backup(backup_list, recovery_target_time): | ||||||||
def choose_backup(backup_list, recovery_target_time, recovery_target_timeline): | ||||||||
hughcapet marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
""" pick up the latest backup file starting before time recovery_target_time""" | ||||||||
|
||||||||
match_timestamp = match = None | ||||||||
for backup in backup_list: | ||||||||
last_modified = parse(backup['last_modified']) | ||||||||
if last_modified < recovery_target_time: | ||||||||
if match is None or last_modified > match_timestamp: | ||||||||
match = backup | ||||||||
match_timestamp = last_modified | ||||||||
timeline_id = int(backup["name"][5:13], 16) | ||||||||
if timeline_id == recovery_target_timeline: | ||||||||
last_modified = parse(backup['last_modified']) | ||||||||
if last_modified < recovery_target_time: | ||||||||
if match is None or last_modified > match_timestamp: | ||||||||
match = backup | ||||||||
match_timestamp = last_modified | ||||||||
if match is not None: | ||||||||
return match['name'] | ||||||||
|
||||||||
|
@@ -140,7 +162,7 @@ def get_wale_environments(env): | |||||||
yield name, orig_value | ||||||||
|
||||||||
|
||||||||
def find_backup(recovery_target_time, env): | ||||||||
def find_backup(recovery_target_time, recovery_target_timeline, env): | ||||||||
old_value = None | ||||||||
for name, value in get_wale_environments(env): | ||||||||
logger.info('Trying %s for clone', value) | ||||||||
|
@@ -150,11 +172,11 @@ def find_backup(recovery_target_time, env): | |||||||
backup_list = list_backups(env) | ||||||||
if backup_list: | ||||||||
if recovery_target_time: | ||||||||
backup = choose_backup(backup_list, recovery_target_time) | ||||||||
backup = choose_backup(backup_list, recovery_target_time, recovery_target_timeline) | ||||||||
if backup: | ||||||||
return backup, (name if value != old_value else None) | ||||||||
else: # We assume that the LATEST backup will be for the biggest postgres version! | ||||||||
return 'LATEST', (name if value != old_value else None) | ||||||||
return get_latest_timeline(), (name if value != old_value else None) | ||||||||
if recovery_target_time: | ||||||||
raise Exception('Could not find any backups prior to the point in time {0}'.format(recovery_target_time)) | ||||||||
raise Exception('Could not find any backups') | ||||||||
|
@@ -163,7 +185,7 @@ def find_backup(recovery_target_time, env): | |||||||
def run_clone_from_s3(options): | ||||||||
env = os.environ.copy() | ||||||||
|
||||||||
backup_name, update_envdir = find_backup(options.recovery_target_time, env) | ||||||||
backup_name, update_envdir = find_backup(options.recovery_target_time, options.recovery_target_timeline, env) | ||||||||
|
||||||||
backup_fetch_cmd = build_wale_command('backup-fetch', options.datadir, backup_name) | ||||||||
logger.info("cloning cluster %s using %s", options.name, ' '.join(backup_fetch_cmd)) | ||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.