Compare commits
12 Commits
2.2.0+2.2.
...
cmd-setup-
| Author | SHA1 | Date | |
|---|---|---|---|
| cd89800fd4 | |||
| 119787ed39 | |||
| 141bedb069 | |||
| 14b55bbc79 | |||
| ebcb0d42c5 | |||
| dccc93ac6b | |||
| 826bec925f | |||
| 49dd989302 | |||
| 2f965a93dc | |||
| 4054d3417e | |||
| f8cfcef029 | |||
| 4a49c4a7f0 |
62
README.md
62
README.md
@ -49,15 +49,23 @@ The backup location can be changed using the `RESTIC_REPOSITORY` env variable.
|
|||||||
|
|
||||||
### S3 Storage
|
### S3 Storage
|
||||||
|
|
||||||
To use S3 storage as backup location set the following envs:
|
1. To use S3 storage as backup location set the following envs:
|
||||||
```
|
```
|
||||||
RESTIC_REPOSITORY=s3:<S3-SERVICE-URL>/<BUCKET-NAME>
|
RESTIC_REPOSITORY=s3:<S3-SERVICE-URL>/<BUCKET-NAME>
|
||||||
SECRET_AWS_SECRET_ACCESS_KEY_VERSION=v1
|
SECRET_AWS_SECRET_ACCESS_KEY_VERSION=v1
|
||||||
AWS_ACCESS_KEY_ID=<MY_ACCESS_KEY>
|
AWS_ACCESS_KEY_ID=<MY_ACCESS_KEY>
|
||||||
COMPOSE_FILE="$COMPOSE_FILE:compose.s3.yml"
|
COMPOSE_FILE="$COMPOSE_FILE:compose.s3.yml"
|
||||||
```
|
```
|
||||||
and add your `<SECRET_ACCESS_KEY>` as docker secret:
|
2. and add your `<SECRET_ACCESS_KEY>` as docker secret:
|
||||||
`abra app secret insert <backupbot_name> aws_secret_access_key v1 <SECRET_ACCESS_KEY>`
|
```
|
||||||
|
abra app secret insert <backupbot_name> aws_secret_access_key v1 <SECRET_ACCESS_KEY>
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Intialze you restic repository:
|
||||||
|
```
|
||||||
|
abra app cmd --chaos <backup_name> app setup_restic_s3
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
See [restic s3 docs](https://restic.readthedocs.io/en/latest/030_preparing_a_new_repo.html#amazon-s3) for more information.
|
See [restic s3 docs](https://restic.readthedocs.io/en/latest/030_preparing_a_new_repo.html#amazon-s3) for more information.
|
||||||
|
|
||||||
@ -157,7 +165,7 @@ Show all files inside the latest snapshot (can be very verbose):
|
|||||||
|
|
||||||
Show specific files inside a selected snapshot:
|
Show specific files inside a selected snapshot:
|
||||||
|
|
||||||
`abra app run <backupbot_name> app -- backup ls --snapshot <snapshot_id> --path /var/lib/docker/volumes/`
|
`abra app run <backupbot_name> app -- backup ls --snapshot <snapshot_id> /var/lib/docker/volumes/`
|
||||||
|
|
||||||
Download files from a snapshot:
|
Download files from a snapshot:
|
||||||
|
|
||||||
@ -179,19 +187,55 @@ restic snapshots
|
|||||||
|
|
||||||
Like Traefik, or `swarm-cronjob`, Backupbot II uses access to the Docker socket to read labels from running Docker Swarm services:
|
Like Traefik, or `swarm-cronjob`, Backupbot II uses access to the Docker socket to read labels from running Docker Swarm services:
|
||||||
|
|
||||||
|
1. Add `ENABLE_BACKUPS=true` to .env.sample
|
||||||
|
|
||||||
|
2. Add backupbot labels to the compose file
|
||||||
|
|
||||||
```
|
```
|
||||||
services:
|
services:
|
||||||
db:
|
db:
|
||||||
deploy:
|
deploy:
|
||||||
labels:
|
labels:
|
||||||
backupbot.backup: ${BACKUP:-"true"}
|
backupbot.backup: "${ENABLE_BACKUPS:-true}"
|
||||||
backupbot.backup.pre-hook: 'mysqldump -u root -p"$(cat /run/secrets/db_root_password)" -f /volume_path/dump.db'
|
backupbot.backup.pre-hook: "/pg_backup.sh backup"
|
||||||
backupbot.backup.post-hook: "rm -rf /volume_path/dump.db"
|
backupbot.backup.volumes.db.path: "backup.sql"
|
||||||
|
backupbot.restore.post-hook: '/pg_backup.sh restore'
|
||||||
|
backupbot.backup.volumes.redis: "false"
|
||||||
```
|
```
|
||||||
|
|
||||||
- `backupbot.backup` -- set to `true` to back up this service (REQUIRED)
|
- `backupbot.backup` -- set to `true` to back up this service (REQUIRED)
|
||||||
- `backupbot.backup.pre-hook` -- command to run before copying files (optional), save all dumps into the volumes
|
- this is the only required backup label, per default it will backup all volumes
|
||||||
- `backupbot.backup.post-hook` -- command to run after copying files (optional)
|
- `backupbot.backup.volumes.<volume_name>.path` -- only backup the listed relative paths from `<volume_name>`
|
||||||
|
- `backupbot.backup.volumes.<volume_name>: false` -- exclude <volume_name> from the backup
|
||||||
|
- `backupbot.backup.pre-hook` -- command to run before copying files
|
||||||
|
- i.e. save all database dumps into the volumes
|
||||||
|
- `backupbot.backup.post-hook` -- command to run after copying files
|
||||||
|
- `backupbot.restore.pre-hook` -- command to run before restoring files
|
||||||
|
- `backupbot.restore.post-hook` -- command to run after restoring files
|
||||||
|
- i.e. read all database dumps from the volumes
|
||||||
|
|
||||||
|
3. (Optional) add backup/restore scripts to the compose file
|
||||||
|
|
||||||
|
```
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
configs:
|
||||||
|
- source: pg_backup
|
||||||
|
target: /pg_backup.sh
|
||||||
|
mode: 0555
|
||||||
|
|
||||||
|
|
||||||
|
configs:
|
||||||
|
pg_backup:
|
||||||
|
name: ${STACK_NAME}_pg_backup_${PG_BACKUP_VERSION}
|
||||||
|
file: pg_backup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Version the config file in `abra.sh`:
|
||||||
|
|
||||||
|
```
|
||||||
|
export PG_BACKUP_VERSION=v1
|
||||||
|
```
|
||||||
|
|
||||||
As in the above example, you can reference Docker Secrets, e.g. for looking up database passwords, by reading the files in `/run/secrets` directly.
|
As in the above example, you can reference Docker Secrets, e.g. for looking up database passwords, by reading the files in `/run/secrets` directly.
|
||||||
|
|
||||||
|
|||||||
4
abra.sh
4
abra.sh
@ -8,3 +8,7 @@ run_cron () {
|
|||||||
while [ ! -f /tmp/backup.log ]; do sleep 1; done
|
while [ ! -f /tmp/backup.log ]; do sleep 1; done
|
||||||
echo "$schedule $(crontab -l | tr -s " " | cut -d ' ' -f6-)" | crontab -
|
echo "$schedule $(crontab -l | tr -s " " | cut -d ' ' -f6-)" | crontab -
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_restic_s3() {
|
||||||
|
AWS_SECRET_ACCESS_KEY=$(cat /run/secrets/aws_secret_access_key) restic -r $RESTIC_REPOSITORY init
|
||||||
|
}
|
||||||
|
|||||||
78
backupbot.py
78
backupbot.py
@ -107,24 +107,26 @@ def create(retries):
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option('snapshot', '--snapshot', '-s', envvar='SNAPSHOT', default='latest')
|
@click.option('snapshot_id', '--snapshot', '-s', envvar='SNAPSHOT', default='latest')
|
||||||
@click.option('target', '--target', '-t', envvar='TARGET', default='/')
|
@click.option('target', '--target', '-t', envvar='TARGET', default='/')
|
||||||
@click.option('noninteractive', '--noninteractive', envvar='NONINTERACTIVE', is_flag=True)
|
@click.option('noninteractive', '--noninteractive', envvar='NONINTERACTIVE', is_flag=True)
|
||||||
@click.option('volumes', '--volumes', '-v', envvar='VOLUMES', multiple=True)
|
@click.option('volumes', '--volumes', '-v', envvar='VOLUMES', multiple=True)
|
||||||
@click.option('container', '--container', '-c', envvar='CONTAINER', multiple=True)
|
@click.option('container', '--container', '-c', envvar='CONTAINER', multiple=True)
|
||||||
@click.option('no_commands', '--no-commands', envvar='NO_COMMANDS', is_flag=True)
|
@click.option('no_commands', '--no-commands', envvar='NO_COMMANDS', is_flag=True)
|
||||||
def restore(snapshot, target, noninteractive, volumes, container, no_commands):
|
def restore(snapshot_id, target, noninteractive, volumes, container, no_commands):
|
||||||
app_settings = parse_backup_labels('restore', container)
|
app_settings = parse_backup_labels('restore', container)
|
||||||
if SERVICE != 'ALL':
|
if SERVICE != 'ALL':
|
||||||
app_settings = {SERVICE: app_settings[SERVICE]}
|
app_settings = {SERVICE: app_settings[SERVICE]}
|
||||||
pre_commands, post_commands, backup_paths, apps_versions = get_backup_details(app_settings, volumes)
|
pre_commands, post_commands, backup_paths, apps_versions = get_backup_details(app_settings, volumes)
|
||||||
snapshots = get_snapshots(snapshot_id=snapshot)
|
snapshots = get_snapshots(snapshot_id)
|
||||||
if not snapshot:
|
if not snapshots:
|
||||||
logger.error(f"No Snapshots with ID {snapshots} for {apps_versions.keys()} found.")
|
logger.error(f"No Snapshots with ID {snapshot_id} for {apps_versions.keys()} found.")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
snapshot = snapshots[0]
|
||||||
|
snapshot_id = snapshot['short_id']
|
||||||
if not noninteractive:
|
if not noninteractive:
|
||||||
print(f"Snapshot to restore: \t{snapshot}")
|
print(f"Snapshot to restore: \t{snapshot_id}")
|
||||||
restore_app_versions = app_versions_from_tags(snapshots[0].get('tags'))
|
restore_app_versions = app_versions_from_tags(snapshot.get('tags'))
|
||||||
print("Apps:")
|
print("Apps:")
|
||||||
for app, version in apps_versions.items():
|
for app, version in apps_versions.items():
|
||||||
restore_version = restore_app_versions.get(app)
|
restore_version = restore_app_versions.get(app)
|
||||||
@ -138,7 +140,7 @@ def restore(snapshot, target, noninteractive, volumes, container, no_commands):
|
|||||||
print("The following commands will be executed:")
|
print("The following commands will be executed:")
|
||||||
for container, cmd in list(pre_commands.items()) + list(post_commands.items()):
|
for container, cmd in list(pre_commands.items()) + list(post_commands.items()):
|
||||||
print(f"\t{container.labels['com.docker.swarm.service.name']}:\t{cmd}")
|
print(f"\t{container.labels['com.docker.swarm.service.name']}:\t{cmd}")
|
||||||
snapshot_date = datetime.fromisoformat(snapshots[0]['time'])
|
snapshot_date = datetime.fromisoformat(snapshot['time'])
|
||||||
delta = datetime.now(tz=timezone.utc) - snapshot_date
|
delta = datetime.now(tz=timezone.utc) - snapshot_date
|
||||||
print(f"This snapshot is {delta} old")
|
print(f"This snapshot is {delta} old")
|
||||||
print("\nTHIS COMMAND WILL IRREVERSIBLY OVERWRITES FILES")
|
print("\nTHIS COMMAND WILL IRREVERSIBLY OVERWRITES FILES")
|
||||||
@ -146,18 +148,18 @@ def restore(snapshot, target, noninteractive, volumes, container, no_commands):
|
|||||||
if prompt != 'YES':
|
if prompt != 'YES':
|
||||||
logger.error("Restore aborted")
|
logger.error("Restore aborted")
|
||||||
exit(1)
|
exit(1)
|
||||||
print(f"Restoring Snapshot {snapshot} at {target}")
|
print(f"Restoring Snapshot {snapshot_id} at {target}")
|
||||||
if not no_commands and pre_commands:
|
if not no_commands and pre_commands:
|
||||||
print(f"Run pre commands.")
|
print(f"Run pre commands.")
|
||||||
run_commands(pre_commands)
|
run_commands(pre_commands)
|
||||||
result = restic_restore(snapshot_id=snapshot, include=backup_paths, target_dir=target)
|
result = restic_restore(snapshot_id=snapshot_id, include=backup_paths, target_dir=target)
|
||||||
if not no_commands and post_commands:
|
if not no_commands and post_commands:
|
||||||
print(f"Run post commands.")
|
print(f"Run post commands.")
|
||||||
run_commands(post_commands)
|
run_commands(post_commands)
|
||||||
logger.debug(result)
|
logger.debug(result)
|
||||||
|
|
||||||
|
|
||||||
def restic_restore(snapshot_id='latest', include=[], target_dir=None):
|
def restic_restore(snapshot_id, include=[], target_dir=None):
|
||||||
cmd = restic.cat.base_command() + ['restore', snapshot_id]
|
cmd = restic.cat.base_command() + ['restore', snapshot_id]
|
||||||
for path in include:
|
for path in include:
|
||||||
cmd.extend(['--include', path])
|
cmd.extend(['--include', path])
|
||||||
@ -188,6 +190,10 @@ def app_versions_from_tags(tags):
|
|||||||
else:
|
else:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
def str2bool(value: str) -> bool:
|
||||||
|
return value.lower() in ("yes", "true", "t", "1")
|
||||||
|
|
||||||
|
|
||||||
def parse_backup_labels(hook_type='backup', selected_container=[]):
|
def parse_backup_labels(hook_type='backup', selected_container=[]):
|
||||||
client = docker.from_env()
|
client = docker.from_env()
|
||||||
container_by_service = {
|
container_by_service = {
|
||||||
@ -201,7 +207,7 @@ def parse_backup_labels(hook_type='backup', selected_container=[]):
|
|||||||
container_name = s.name.removeprefix(f"{stack_name}_")
|
container_name = s.name.removeprefix(f"{stack_name}_")
|
||||||
version = labels.get(f'coop-cloud.{stack_name}.version')
|
version = labels.get(f'coop-cloud.{stack_name}.version')
|
||||||
settings = app_settings[stack_name] = app_settings.get(stack_name) or {}
|
settings = app_settings[stack_name] = app_settings.get(stack_name) or {}
|
||||||
if (backup := labels.get('backupbot.backup')) and bool(backup):
|
if (backup := labels.get('backupbot.backup')) and str2bool(backup):
|
||||||
settings['enabled'] = True
|
settings['enabled'] = True
|
||||||
if version:
|
if version:
|
||||||
settings['version'] = version
|
settings['version'] = version
|
||||||
@ -302,7 +308,7 @@ def parse_excludes_includes(labels):
|
|||||||
if label.endswith('path'):
|
if label.endswith('path'):
|
||||||
relative_paths = tuple(value.split(','))
|
relative_paths = tuple(value.split(','))
|
||||||
included_volume_paths.add((volume_name, relative_paths))
|
included_volume_paths.add((volume_name, relative_paths))
|
||||||
elif bool(value):
|
elif not str2bool(value):
|
||||||
excluded_volumes.add(volume_name)
|
excluded_volumes.add(volume_name)
|
||||||
return excluded_volumes, included_volume_paths
|
return excluded_volumes, included_volume_paths
|
||||||
|
|
||||||
@ -353,14 +359,14 @@ def run_commands(commands):
|
|||||||
logger.error(
|
logger.error(
|
||||||
f"Failed to run command {command} in {container.name}: {result.output.decode()}")
|
f"Failed to run command {command} in {container.name}: {result.output.decode()}")
|
||||||
else:
|
else:
|
||||||
logger.info(result.output.decode())
|
logger.debug(result.output.decode())
|
||||||
|
|
||||||
|
|
||||||
def backup_volumes(backup_paths, apps_versions, retries, dry_run=False):
|
def backup_volumes(backup_paths, apps_versions, retries, dry_run=False):
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
logger.info("Backup these paths:")
|
logger.info("Backup these paths:")
|
||||||
logger.debug("\n".join(map(str, backup_paths)))
|
logger.info("\n".join(map(str, backup_paths)))
|
||||||
backup_paths = list(filter(path_exists, backup_paths))
|
backup_paths = list(filter(path_exists, backup_paths))
|
||||||
cmd = restic.cat.base_command()
|
cmd = restic.cat.base_command()
|
||||||
parent = get_snapshots('latest')
|
parent = get_snapshots('latest')
|
||||||
@ -409,22 +415,31 @@ def snapshots():
|
|||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option('snapshot', '--snapshot', '-s', envvar='SNAPSHOT', default='latest')
|
@click.option('snapshot', '--snapshot', '-s', envvar='SNAPSHOT', default='latest')
|
||||||
@click.option('path', '--path', '-p', envvar='INCLUDE_PATH')
|
@click.option('show_all', '--all', '-a', envvar='SHOW_ALL', is_flag=True)
|
||||||
def ls(snapshot, path):
|
@click.option('timestamps', '--timestamps', '-t', envvar='TIMESTAMPS', is_flag=True)
|
||||||
results = list_files(snapshot, path)
|
@click.argument('path', required=False, default='/var/lib/docker/volumes/')
|
||||||
for r in results:
|
def ls(snapshot, show_all, timestamps, path):
|
||||||
if r.get('path'):
|
|
||||||
print(f"{r['ctime']}\t{r['path']}")
|
|
||||||
|
|
||||||
|
|
||||||
def list_files(snapshot, path):
|
|
||||||
cmd = restic.cat.base_command() + ['ls']
|
|
||||||
if snapshot == 'latest':
|
if snapshot == 'latest':
|
||||||
latest_snapshot = get_snapshots('latest')
|
latest_snapshot = get_snapshots('latest')
|
||||||
if not latest_snapshot:
|
if not latest_snapshot:
|
||||||
logger.error(f"There is no latest snapshot for {SERVICE}")
|
logger.error(f"There is no latest snapshot for {SERVICE}")
|
||||||
exit(1)
|
exit(1)
|
||||||
snapshot = latest_snapshot[0]['short_id']
|
snapshot = latest_snapshot[0]['short_id']
|
||||||
|
if os.environ.get('INCLUDE_PATH'):
|
||||||
|
path = os.environ.get('INCLUDE_PATH')
|
||||||
|
if show_all:
|
||||||
|
path = None
|
||||||
|
results = list_files(snapshot, path)
|
||||||
|
for r in results:
|
||||||
|
if r.get('path'):
|
||||||
|
if timestamps:
|
||||||
|
print(f"{r['ctime']}\t{r['path']}")
|
||||||
|
else:
|
||||||
|
print(f"{r['path']}")
|
||||||
|
|
||||||
|
|
||||||
|
def list_files(snapshot, path):
|
||||||
|
cmd = restic.cat.base_command() + ['ls']
|
||||||
cmd.append(snapshot)
|
cmd.append(snapshot)
|
||||||
if path:
|
if path:
|
||||||
cmd.append(path)
|
cmd.append(path)
|
||||||
@ -451,6 +466,12 @@ def list_files(snapshot, path):
|
|||||||
@click.option('secrets', '--secrets', '-c', is_flag=True, envvar='SECRETS')
|
@click.option('secrets', '--secrets', '-c', is_flag=True, envvar='SECRETS')
|
||||||
def download(snapshot, path, volumes, secrets):
|
def download(snapshot, path, volumes, secrets):
|
||||||
file_dumps = []
|
file_dumps = []
|
||||||
|
if snapshot == 'latest':
|
||||||
|
latest_snapshot = get_snapshots('latest')
|
||||||
|
if not latest_snapshot:
|
||||||
|
logger.error(f"There is no latest snapshot for {SERVICE}")
|
||||||
|
exit(1)
|
||||||
|
snapshot = latest_snapshot[0]['short_id']
|
||||||
if not any([path, volumes, secrets]):
|
if not any([path, volumes, secrets]):
|
||||||
volumes = secrets = True
|
volumes = secrets = True
|
||||||
if path:
|
if path:
|
||||||
@ -515,13 +536,6 @@ def get_formatted_size(file_path):
|
|||||||
|
|
||||||
def dump(snapshot, path):
|
def dump(snapshot, path):
|
||||||
cmd = restic.cat.base_command() + ['dump']
|
cmd = restic.cat.base_command() + ['dump']
|
||||||
if snapshot == 'latest':
|
|
||||||
latest_snapshot = get_snapshots('latest')
|
|
||||||
if not latest_snapshot:
|
|
||||||
logger.error(f"There is no latest snapshot for {SERVICE}")
|
|
||||||
exit(1)
|
|
||||||
snapshot = latest_snapshot[0]['short_id']
|
|
||||||
cmd.append(snapshot)
|
|
||||||
cmd = cmd + [snapshot, path]
|
cmd = cmd + [snapshot, path]
|
||||||
print(f"Dumping {path} from snapshot '{snapshot}'")
|
print(f"Dumping {path} from snapshot '{snapshot}'")
|
||||||
output = subprocess.run(cmd, capture_output=True)
|
output = subprocess.run(cmd, capture_output=True)
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
version: "3.8"
|
version: "3.8"
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
image: git.coopcloud.tech/coop-cloud/backup-bot-two:2.2.1-beta
|
image: git.coopcloud.tech/coop-cloud/backup-bot-two:2.3.0-beta
|
||||||
volumes:
|
volumes:
|
||||||
- "/var/run/docker.sock:/var/run/docker.sock"
|
- "/var/run/docker.sock:/var/run/docker.sock"
|
||||||
- "/var/lib/docker/volumes/:/var/lib/docker/volumes/"
|
- "/var/lib/docker/volumes/:/var/lib/docker/volumes/"
|
||||||
@ -16,7 +16,7 @@ services:
|
|||||||
- restic_password
|
- restic_password
|
||||||
deploy:
|
deploy:
|
||||||
labels:
|
labels:
|
||||||
- coop-cloud.${STACK_NAME}.version=2.2.0+2.2.1-beta
|
- coop-cloud.${STACK_NAME}.version=2.3.0+2.3.0-beta
|
||||||
- coop-cloud.${STACK_NAME}.timeout=${TIMEOUT:-300}
|
- coop-cloud.${STACK_NAME}.timeout=${TIMEOUT:-300}
|
||||||
- coop-cloud.backupbot.enabled=true
|
- coop-cloud.backupbot.enabled=true
|
||||||
#entrypoint: ['tail', '-f','/dev/null']
|
#entrypoint: ['tail', '-f','/dev/null']
|
||||||
|
|||||||
34
pg_backup.sh
Normal file
34
pg_backup.sh
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
BACKUP_FILE='/var/lib/postgresql/data/backup.sql'
|
||||||
|
|
||||||
|
function backup {
|
||||||
|
export PGPASSWORD=$(cat $POSTGRES_PASSWORD_FILE)
|
||||||
|
pg_dump -U ${POSTGRES_USER} ${POSTGRES_DB} > $BACKUP_FILE
|
||||||
|
}
|
||||||
|
|
||||||
|
function restore {
|
||||||
|
cd /var/lib/postgresql/data/
|
||||||
|
restore_config(){
|
||||||
|
# Restore allowed connections
|
||||||
|
cat pg_hba.conf.bak > pg_hba.conf
|
||||||
|
su postgres -c 'pg_ctl reload'
|
||||||
|
}
|
||||||
|
# Don't allow any other connections than local
|
||||||
|
cp pg_hba.conf pg_hba.conf.bak
|
||||||
|
echo "local all all trust" > pg_hba.conf
|
||||||
|
su postgres -c 'pg_ctl reload'
|
||||||
|
trap restore_config EXIT INT TERM
|
||||||
|
|
||||||
|
# Recreate Database
|
||||||
|
psql -U ${POSTGRES_USER} -d postgres -c "DROP DATABASE ${POSTGRES_DB} WITH (FORCE);"
|
||||||
|
createdb -U ${POSTGRES_USER} ${POSTGRES_DB}
|
||||||
|
psql -U ${POSTGRES_USER} -d ${POSTGRES_DB} -1 -f $BACKUP_FILE
|
||||||
|
|
||||||
|
trap - EXIT INT TERM
|
||||||
|
restore_config
|
||||||
|
}
|
||||||
|
|
||||||
|
$@
|
||||||
Reference in New Issue
Block a user