Developer’s Guide

Low level API

You can access low level API (the same used when using bakthat in command line mode) from bakthat root module.

import bakthat

# roration is optional
bakthat_conf = {'access_key': 'YOURACCESSKEY',
                'secret_key': 'YOURSECRETKEY',
                'glacier_vault': 'yourvault',
                's3_bucket': 'yours3bucket',
                'region_name': 'eu-west-1',
                'rotation': {'days': 7,
                            'first_week_day': 5,
                            'months': 6,
                            'weeks': 6}}

bakthat.backup("/dir/i/wanto/bak", conf=bakthat_conf)

bakthat.backup("/dir/i/wanto/bak", conf=bakthat_conf, destination="glacier")

# or if you want to have generated the configuration file with "bakthat configure" or created ~/.bakthat.yml
bakthat.backup("/dir/i/wanto/bak")

bakthat.ls()

# restore in the current working directory
bakthat.restore("bak", conf=bakthat_conf)

Event Hooks

New in version 0.6.0.

You can configure hook to be executed on the following events:

  • before_backup
  • on_backup
  • before_restore
  • on_restore
  • before_delete
  • on_delete
  • before_delete_older_than
  • on_delete_older_than
  • before_rotate_backups
  • on_rotate_backups

So, before_ events are executed at the beginning of the action, and on_ events are executed just before the end.

For each action, a session_id (an uuid4) is assigned, so you can match up before_ and on_ events.

Every callback receive the session_id as first argument, and for on_ callbacks, you can retrieve the result of the function, most of the time a Backup object or a list of Backup object, depending of the context.

from bakthat import backup, events

def before_backup_callback(session_id):
    print session_id, "before_backup"

def on_backup_callback(session_id, backup):
    print session_id, "on_backup", backup

events.before_backup += before_backup_callback
events.on_backup += on_backup_callback

bakthat.backup("/home/thomas/mydir")

Bakthat makes use of Events to handle all the “event things”.

Plugins

New in version 0.6.0.

You can create plugins to extend bakthat features, all you need to do is to subclass bakthat.plugin.Plugin and implement an activate (and optionally deactivate, executed just before exiting) method.

The activate and deactivate method is called only once. activate is called when the plugin is initialized, and deactivate (you can see it like a cleanup function) is called at exit.

Note

For now, you can’t create new command yet with plugin (maybe in the future).

By default, plugins are stored in ~/.bakthat_plugins/, but you can change the plugins location by setting the plugins_dir setting in your configuration file.

default:
  plugins_dir: /home/thomas/.bakthat_plugins

And to enable plugins, add it to the plugins array:

default:
  plugins: [test_plugin.TestPlugin, filename.MyPlugin]

You can access raw profile configuration using self.conf, and bakthat logger using self.log (e.g. self.log.info("hello")) and in any methods. You can also hook events directly on self, like self.on_backup += mycallback.

Your First Plugin

Here is a basic plugin example, a TimerPlugin in test_plugin.py:

import time
from bakthat.plugin import Plugin

class TestPlugin(Plugin):
    def activate(self):
        self.start = {}
        self.stop = {}
        self.before_backup += self.before_backup_callback
        self.on_backup += self.on_backup_callback

    def before_backup_callback(self, session_id):
        self.start[session_id] = time.time()
        self.log.info("before_backup {0}".format(session_id))

    def on_backup_callback(self, session_id, backup):
        self.stop[session_id] = time.time()
        self.log.info("on_backup {0} {1}".format(session_id, backup))
        self.log.info("Job duration: {0}s".format(self.stop[session_id] - self.start[session_id]))

Now, we can enable it:

default:
  plugins: [test_plugin.TestPlugin]

Finally, we can check that our plugin is actually working:

$ bakthat backup mydir
before_backup 4028dfc7-7a17-4a99-b3fe-88f6e4879bda
Backing up /home/thomas/mydir
Password (blank to disable encryption):
Compressing...
Uploading...
Upload completion: 0%
Upload completion: 100%
Upload completion: 0%
Upload completion: 100%
on_backup 4028dfc7-7a17-4a99-b3fe-88f6e4879bda <Backup: mydir.20130604191055.tgz>
Job duration: 4.34407806396s

Monkey Patching

With plugin, you have the ability to extend or modify everything in the activate function.

Here is an example, which update the Backups model at runtime:

from bakthat.plugin import Plugin
from bakthat.models import Backups


class MyBackups(Backups):
    @classmethod
    def my_custom_method(self):
        return True


class ChangeModelPlugin(Plugin):
    """ A basic plugin implementation. """
    def activate(self):
        global Backups
        self.log.info("Replace Backups")
        Backups = MyBackups

More on event hooks

See Event Hooks for more informations and Events documentation.

Helpers

BakHelper

BakHelper is a context manager that makes create backup script with bakthat (and it works well with sh) an easy task.

It takes care of create a temporary directory and make it the current working directory so you can just dump files to backup or call system command line tool lilke mysqldump/mongodump/and so on with the help of sh.

Here is a minimal example.

import logging
logging.basicConfig(level=logging.INFO)

from bakthat.helper import BakHelper

with BakHelper("mybackup", tags=["mybackup"]) as bh:

    with open("myfile.txt", "w") as f:
        f.write("mydata")

    bh.backup()
    bh.rotate()

Now test the script:

$ python mybackupscript.py
INFO:root:Backing up /tmp/mybackup_JVTGOM
INFO:root:Compressing...
INFO:root:Uploading...
INFO:bakthat.backends:Upload completion: 0%
INFO:bakthat.backends:Upload completion: 100%

You can also use it like a normal class:

import logging
import sh
logging.basicConfig(level=logging.INFO)

from bakthat.helper import BakHelper

bakthat_conf = {'access_key': 'YOURACCESSKEY',
                'secret_key': 'YOURSECRETKEY',
                'glacier_vault': 'yourvault',
                's3_bucket': 'yours3bucket',
                'region_name': 'eu-west-1',
                'rotation': {'days': 7,
                            'first_week_day': 5,
                            'months': 6,
                            'weeks': 6}}

bh = BakHelper(conf=bakthat_conf)
with open("myfile.txt", "w") as f:
    f.write("mydata")
bh.backup("myfile.txt")
bh.rotate("myfile.txt")

Create a MySQL backup script with BakHelper

Here is a MySQL backup script, it makes use of sh to call system mysqldump.

See also

You can also check out a MongoDB backup script example here.

import logging
import sh
logging.basicConfig(level=logging.INFO)

from bakthat.helper import BakHelper

BACKUP_NAME = "myhost_mysql"
BACKUP_PASSWORD = "mypassword"
MYSQL_USER = "root"
MYSQL_PASSWORD = "mypassword"

with BakHelper(BACKUP_NAME, password=BACKUP_PASSWORD, tags=["mysql"]) as bh:
    sh.mysqldump("-p{0}".format(MYSQL_PASSWORD),
                u=MYSQL_USER,
                all_databases=True,
                _out="dump.sql")
    bh.backup()
    bh.rotate()

KeyValue

New in version 0.4.5.

KeyValue is a simple “key value store” that allows you to quickly store/retrieve strings/objects on Amazon S3. All values are serialized with json, so you can directly backup any json serializable value.

It can also takes care of compressing (with gzip) and encrypting (optionnal).

Compression in enabled by default, you can disable it by passing compress=False when setting a key.

Also, backups stored with KeyValue can be restored with bakthat restore and show up in bakthat show.

from bakthat.helper import KeyValue
import json

bakthat_conf = {'access_key': 'YOURACCESSKEY',
                'secret_key': 'YOURSECRETKEY',
                'glacier_vault': 'yourvault',
                's3_bucket': 'yours3bucket',
                'region_name': 'es-east-1'}

kv = KeyValue(conf=bakthat_conf)

mydata = {"some": "data"}
kv.set_key("mykey", mydata)

mydata_restored = kv.get_key("mykey")

data_url = kv.get_key_url("mykey", 60)  # url expires in 60 secondes

kv.delete_key("mykey")

kv.set_key("my_encrypted_key", "myvalue", password="mypassword")
kv.get_key("my_encrypted_key", password="mypassword")

# You can also disable gzip compression if you want:
kv.set_key("my_non_compressed_key", {"my": "data"}, compress=False)

Accessing bakthat SQLite database

Since bakthat stores custom backups metadata (see Stored metadata), you can execute custom SQL query.