diff options
| -rw-r--r-- | README.md | 21 | ||||
| -rw-r--r-- | config.yaml | 12 | ||||
| -rwxr-xr-x | hooks/hooks.py | 60 | ||||
| -rw-r--r-- | revision | 2 | ||||
| -rwxr-xr-x | templates/backup.py.tpl | 53 | 
5 files changed, 147 insertions, 1 deletions
| @@ -165,6 +165,18 @@ A sample of the default settings of the config.yaml file at the time of writing  default: "none"  type: string  description: Extra options ( exactly as you would type them in the command line ) to be added via the command line to the mongodb daemon + backups_enabled: + default: False + type: boolean + description: Enable daily backups to disk. + backup_directory: + default: "/home/ubuntu/backups" + type: string + description: Where can the backups be found. + backup_copies_kept: + default: 7 + type: int + description: Number of backups to keep. Keeps one week's worth by default.  ### Where: @@ -315,6 +327,15 @@ To verify that your sharded cluster is running, connect to the mongo shell and r  - run sh.status()  You should see your the hosts for your shards in the status output. +## Backups + +Backups can be enabled via config. Note that destroying the service cannot +currently remove the backup cron job so it will continue to run. There is a +setting for the number of backups to keep, however, to prevent from filling +disk space. + +To fetch the backups scp the files down from the path in the config. +  # Troubleshooting diff --git a/config.yaml b/config.yaml index 969d45e..9709f88 100644 --- a/config.yaml +++ b/config.yaml @@ -143,3 +143,15 @@ options:  default: "none"  type: string  description: Extra options ( exactly as you would type them in the command line ) to be added via the command line to the mongodb daemon + backups_enabled: + default: False + type: boolean + description: Enable daily backups to disk. + backup_directory: + default: "/home/ubuntu/backups" + type: string + description: Where can the backups be found. + backup_copies_kept: + default: 7 + type: int + description: Number of backups to keep. Keeps one week's worth by default. diff --git a/hooks/hooks.py b/hooks/hooks.py index 1fcaa46..a4427b9 100755 --- a/hooks/hooks.py +++ b/hooks/hooks.py @@ -14,6 +14,10 @@ import signal  import socket  import time +from os import chmod +from os import remove +from os.path import exists +from string import Template  ###############################################################################  # Supporting functions @@ -826,6 +830,56 @@ def restart_mongod(wait_for=default_wait_for, max_tries=default_max_tries):  is True) +def backup_cronjob(disable=False): + """Generate the cronjob to backup with mongodbump.""" + juju_log('Setting up cronjob') + config_data = config_get() + backupdir = config_data['backup_directory'] + bind_ip = config_data['bind_ip'] + cron_file = '/etc/cron.d/mongodb' + cron_runtime = '@daily' + cron_runtime = '*/2 * * * *' + + # Disable or not remove it and regenerate it with new config data. + if exists(cron_file): + remove(cron_file) + + if not disable: + tpl_data = { + 'backup_copies': config_data['backup_copies_kept'], + 'backup_directory': backupdir, + 'unique_name': os.environ.get('JUJU_UNIT_NAME', bind_ip), + 'bind_ip': bind_ip, + 'port': config_data['port'], + } + + script_filename = '/var/lib/mongodb/cronbackup.py' + script_template = 'templates/backup.py.tpl' + + juju_log('Writing out cronbackup.py') + with open(script_template) as handle: + template = Template(handle.read()) + rendered = template.substitute(tpl_data) + + with open(script_filename, 'w') as output: + output.writelines(rendered) + chmod(script_filename, 0755) + + juju_log('Installing cron.d/mongodb') + + if exists(cron_file): + remove(cron_file) + + with open(cron_file, 'w') as output: + output.write(""" +SHELL=/bin/bash +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +%s ubuntu python %s + +""" % (cron_runtime, script_filename)) + +  ###############################################################################  # Hook functions  ############################################################################### @@ -835,6 +889,7 @@ def install_hook():  juju_log("Installation of mongodb failed.")  return(False)  else: +  return(True) @@ -860,6 +915,11 @@ def config_changed():  mongodb_config = mongodb_conf(config_data)  update_file(default_mongodb_config, mongodb_config) + if config_data['backups_enabled']: + backup_cronjob() + else: + backup_cronjob(disable=True) +  # web_admin_ui  if config_data['web_admin_ui']:  enable_web_admin_ui(new_web_admin_ui_port) @@ -1 +1 @@ -25 +31 diff --git a/templates/backup.py.tpl b/templates/backup.py.tpl new file mode 100755 index 0000000..bb1f079 --- /dev/null +++ b/templates/backup.py.tpl @@ -0,0 +1,53 @@ +#!/usr/bin/env python +"""Generate the cronjob to backup with mongodbump.""" + +from os import chdir +from os import listdir +from os import remove +from os.path import exists +from os.path import join +from datetime import datetime +from shutil import rmtree +import subprocess +from tempfile import mkdtemp + + +when = datetime.now() +backupdir = '$backup_directory' +tmpdir = mkdtemp() + +# Clean up any old backup copies. +current_backups = listdir(backupdir) +current_backups.sort() +for file in current_backups[0:-$backup_copies]: + remove(join(backupdir, file)) + +chdir(tmpdir) + +# Make sure the directory to stick tarballs exist. +if not exists(backupdir): + subprocess.call([ + 'mkdir', + '-p', + backupdir, + ]) + +# Generate a pretty unique backup filename. +# The unique name might have slashes in it so replace them. +backup_filename = "%s/%s-%s.tar.gz" % ( + backupdir, + '$unique_name'.replace('/', '-'), + when.strftime("%Y%m%d-%H%M%S"), +) + +# mongodump creates a directory per db. Drop them all in a tmpdir and then +# we'll tar it up as step 2. +dump = '/usr/bin/mongodump --host 127.0.0.1:$port' +subprocess.call(dump, shell=True) + +# Generate the ta +tar = 'tar czvf %s dump/*' % backup_filename +subprocess.call(tar, shell=True) + +# Clean up the tmpdir. +rmtree(tmpdir) | 
