-
Notifications
You must be signed in to change notification settings - Fork 447
in place major upgrade #488
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
Changes from all commits
e328182
9f0320a
fc47c58
be18343
342da9f
eec5b9a
cf37c6d
10260ff
d0eb6b4
a9cf41e
936a90b
590917a
3a5b988
2bf0a67
2aa408f
862acc9
23e71f1
ad68923
592306e
4f22981
92442de
a7a4cd7
13e9567
5ed144d
eb45869
67caf5b
1b49069
c64fe33
28217e3
1a0a436
7c70d96
7903d61
722d63f
06b26ee
6e3c87f
3c5f6f5
4c36a50
92e69b0
aef8a98
35349b9
c1cf441
179b825
c5981d5
32a5243
a1685da
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 |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |
| import logging | ||
| import os | ||
| import re | ||
| import shlex | ||
| import subprocess | ||
| import sys | ||
|
|
||
|
|
@@ -61,36 +62,115 @@ def fix_output(output): | |
| yield '\t'.join(line.split()) | ||
|
|
||
|
|
||
| def choose_backup(output, recovery_target_time): | ||
| def choose_backup(backup_list, recovery_target_time): | ||
| """ pick up the latest backup file starting before time recovery_target_time""" | ||
| reader = csv.DictReader(fix_output(output), dialect='excel-tab') | ||
| backup_list = list(reader) | ||
| if len(backup_list) <= 0: | ||
| raise Exception("wal-e could not found any backups") | ||
|
|
||
| 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 | ||
| if match is None: | ||
| raise Exception("wal-e could not found any backups prior to the point in time {0}".format(recovery_target_time)) | ||
| return match['name'] | ||
| if match is not None: | ||
| return match['name'] | ||
|
|
||
|
|
||
| def list_backups(env): | ||
| backup_list_cmd = build_wale_command('backup-list') | ||
| output = subprocess.check_output(backup_list_cmd, env=env) | ||
| reader = csv.DictReader(fix_output(output), dialect='excel-tab') | ||
| return list(reader) | ||
|
|
||
|
|
||
| def get_clone_envdir(): | ||
| from spilo_commons import get_patroni_config | ||
|
|
||
| config = get_patroni_config() | ||
| restore_command = shlex.split(config['bootstrap']['clone_with_wale']['recovery_conf']['restore_command']) | ||
| if len(restore_command) > 4 and restore_command[0] == 'envdir': | ||
| return restore_command[1] | ||
| raise Exception('Failed to find clone envdir') | ||
|
|
||
|
|
||
| def get_possible_versions(): | ||
| from spilo_commons import LIB_DIR, get_binary_version, get_bin_dir, get_patroni_config | ||
|
|
||
| config = get_patroni_config() | ||
|
|
||
| max_version = float(get_binary_version(config.get('postgresql', {}).get('bin_dir'))) | ||
|
|
||
| versions = {} | ||
|
|
||
| for d in os.listdir(LIB_DIR): | ||
| try: | ||
| ver = get_binary_version(get_bin_dir(d)) | ||
| fver = float(ver) | ||
| if fver <= max_version: | ||
| versions[fver] = ver | ||
| except Exception: | ||
| pass | ||
|
|
||
| # return possible versions in reversed order, i.e. 12, 11, 10, 9.6, and so on | ||
| return [ver for _, ver in sorted(versions.items(), reverse=True)] | ||
|
|
||
|
|
||
| def get_wale_environments(env): | ||
| use_walg = env.get('USE_WALG_RESTORE') == 'true' | ||
| prefix = 'WALG_' if use_walg else 'WALE_' | ||
| # len('WALE__PREFIX') = 12 | ||
| names = [name for name in env.keys() if name.endswith('_PREFIX') and name.startswith(prefix) and len(name) > 12] | ||
| if len(names) != 1: | ||
| raise Exception('Found find {0} {1}*_PREFIX environment variables, expected 1' | ||
| .format(len(names), prefix)) | ||
|
|
||
| name = names[0] | ||
| value = env[name].rstrip('/') | ||
|
|
||
| if '/spilo/' in value and value.endswith('/wal'): # path crafted in the configure_spilo.py? | ||
| # Try all versions descending if we don't know the version of the source cluster | ||
| for version in get_possible_versions(): | ||
| yield name, '{0}/{1}/'.format(value, version) | ||
|
|
||
| # Last, try the original value | ||
| yield name, env[name] | ||
|
|
||
|
|
||
| def find_backup(recovery_target_time, env): | ||
| old_value = None | ||
| for name, value in get_wale_environments(env): | ||
| if not old_value: | ||
| old_value = env[name] | ||
| env[name] = value | ||
| backup_list = list_backups(env) | ||
| if backup_list: | ||
| if recovery_target_time: | ||
| backup = choose_backup(backup_list, recovery_target_time) | ||
| 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! | ||
|
Member
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. to what does the "biggest" refer in this comment ? Does it meant the
Contributor
Author
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. If we don't have the major version of the source cluster specified explicitly we try all postgres versions starting from the biggest. I.e.,
For every prefix we call But! It might be, that under the |
||
| return 'LATEST', (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') | ||
|
|
||
|
|
||
| def run_clone_from_s3(options): | ||
| backup_name = 'LATEST' | ||
| if options.recovery_target_time: | ||
| backup_list_cmd = build_wale_command('backup-list') | ||
| backup_list = subprocess.check_output(backup_list_cmd) | ||
| backup_name = choose_backup(backup_list, options.recovery_target_time) | ||
| env = os.environ.copy() | ||
|
|
||
| backup_name, update_envdir = find_backup(options.recovery_target_time, 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)) | ||
| if not options.dry_run: | ||
| ret = subprocess.call(backup_fetch_cmd) | ||
| ret = subprocess.call(backup_fetch_cmd, env=env) | ||
| if ret != 0: | ||
| raise Exception("wal-e backup-fetch exited with exit code {0}".format(ret)) | ||
|
|
||
| if update_envdir: # We need to update file in the clone envdir or restore_command will fail! | ||
| envdir = get_clone_envdir() | ||
| with open(os.path.join(envdir, update_envdir), 'w') as f: | ||
| f.write(env[update_envdir]) | ||
| return 0 | ||
|
|
||
|
|
||
|
|
||
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.