Backup and restore all iApps

Problem this snippet solves:

Backup all of your iApps to a local SQLLite3 database.

I mostly use this code in a Jupyter browser on my windows machine (before making major changes to our iApps or F5s). Using it via the CLI will allow for a simple backup database to be created but it lacks simple CLI tools (like restoring from the CLI, etc.)

Hopefully you can find some use for it.

How to use this snippet:

Usage: python f5_backup.py

Code :

from __future__ import print_function

from datadiff import diff
from datadiff.tools import assert_equal
import arrow # Improved datetime module
import pickle
import sqlite3
import bigsuds

''' F5 iApp backup and restore utility (using SQLLite)

    This utility performs basic backup and restoration of iApps from a local
    SQLite database.

    @REQUIRES:
    pip install arrow
    pip install bigsuds
    pip install datadiff

    @TODO:
    Implement versioning system to keep track of incremental changes.
    This will allow us to roll backwards or forwards between iApp versions.

    Mitch Mahan
    mitchm87@gmail.com
    01-19-2017
    '''

def f5_dict(x):
    ''' Convert the iApp variables from the F5 API into a more human-readable
        dictionary. May help us work with the datastructures in the future?
        '''
    return {
                x[0]: # The iApp Name
                {
                    "template": x[1],
                    "list_vars": x[2],
                    "scalar_vars": x[3],
                    "table": x[4]
                }
            }

def gather_data_from_api(c):
    ''' Gather all of the variables from the active F5 LTM connection.

        @INPUT: object(c) - bigsuds API connection
        @OUTPUT: list(dict()) of iApps
        '''
    iapps = c.Management.ApplicationService.get_list()
    template = c.Management.ApplicationService.get_template(iapps)
    list_ = c.Management.ApplicationService.get_list_vars(iapps)
    scalar_ = c.Management.ApplicationService.get_scalar_vars(iapps)
    table_ = c.Management.ApplicationService.get_table_vars(iapps)
    return map(lambda x: f5_dict(x), zip(iapps,template,list_,scalar_,table_))

def restore_from_db(iapp_name, c):
    ''' Restore an iApp from the local database given its full name.

        Example: restore_from_db('/Common/company.com.app/company.com')
        '''
    name = iapp_name.split('/')[2]
    sql = connect_db().cursor()
    sql.execute("SELECT vars FROM iapps WHERE device=? and iapp=?",
                          (c._hostname, iapp_name))
    iapp = pickle.loads(sql.fetchone()[0])
    c.Management.ApplicationService.create(
        [name],
        [iapp['template']],
        [iapp['scalar_vars']],
        [iapp['list_vars']],
        [iapp['table']]
    )

def save_iapp_to_db(iapp, iapp_vars, device):
    ''' Save a new record entry into the database. '''
    db = connect_db()
    sql = db.cursor()
    vars_ = pickle.dumps(iapp_vars)
    data = (str(arrow.now()), device, iapp, vars_)
    sql.execute(
        'INSERT INTO iapps(date, device, iapp, vars) VALUES (?,?,?,?)',
        data
    )
    db.commit()
    return True

def save_iapps(iapps_with_vars, c):
    ''' Loop through each iApp and determine if the databse version matches
        the current version on the F5. If the running iApp and database iApp
        are different then save the entire iApp as a new version to the
        database.
        '''
    db = connect_db()
    sql = db.cursor()
    for iapp in iapps_with_vars:
        name = iapp.keys()[0]
        print(name)
        try:
            sql.execute("SELECT vars FROM iapps WHERE device=? and iapp=?",
                          (str(c._hostname), name))
            db_iapp = pickle.loads(sql.fetchone()[0])
        except:
            print("\t! No entry in database.")
            db_iapp = False
        try:
            assert_equal(iapp[name], db_iapp)
            print("\t+ Entry already in database.")
        except AssertionError:
            print("\t+ Saving to database.".format(name))
            #diff(iapp[name], db_iapp)
            save_iapp_to_db(name, iapp[name], str(c._hostname))

def connect(device, username, password):
    try:
        return bigsuds.BIGIP(
            hostname = device,
            username = username,
            password = password
        )
    except:
        print("Unable to connect to device. Examine connectivity.")

def connect_db():
    ''' Connect to the local SQL Lite database.

        Feel free to change the name of the database file.'''
    database_file = 'f5_iapps.db'
    return sqlite3.connect(database_file)

def main():
    ''' Backup all of the existing iApps to a local SQLLite file '''
    device = ''
    username = ''
    password = ''
    c = connect(device, username, password)
    db = connect_db()
    try:
        sql = db.cursor()
        # Create iapps table
        sql.execute('''CREATE TABLE iapps
             (date text, device text, iapp text, vars text)''')
    except sqlite3.OperationalError:
        pass
    # To grab iapps from all partitions, move to the root
    c.System.Session.set_active_folder('/')
    # Do recursive lookups
    c.System.Session.set_recursive_query_state("STATE_ENABLED")
    iapps_with_vars = gather_data_from_api(c)
    save_iapps(iapps_with_vars, c)

if __name__ == "__main__":
    main()

Tested this on version:

12.0
Published May 12, 2017
Version 1.0

Was this article helpful?

No CommentsBe the first to comment