четверг, 21 ноября 2013 г.

PUBS - Python universal backup script для linux

Данный скрипт был наваян мной в целях автоматизации процессов резервного копирования. Основным назначением является создание резервных копий (архивов с данными) как на локальном хранилище linux серверов, так и их дальнейшее дублирование на удалённом хранилище, которое расположено на windows сервере (зеркало).

В целом такая вот картинка....


Что делает мой скрипт (пошагово):

1. Сначала проверяет доступен ли удалённый windows server, проверяя состояние открытости порта netbios (по умолчанию 135 порт)
2. Затем проверяет запущен ли mysql на локальной машине (по умолчанию 127.0.0.1), проверяя возможность соединиться с портом mysql (по умолчанию 3306).
3. Если проверки прошли удачно, то скрипт начинает монтировать удалённую расшаренную директорию на windows сервере к директории, расположенной на локальном сервере.
3. Если монтирование прошло удачно, то скрипт создаёт новую директорию с именем, отражающим текущую дату в директории на локальном сервере (на примере /backup/20131121/).
4. Далее создаются дампы баз данных, имена которых указаны в переменных скрипта и складируются в ранее созданную директорию (к примеру складируются в  /backup/20131121/, с именами в формате mysql-имя базы-.sql.годмесяцдень.часминутасекунда.gz)
5. Затем пакуются директории в виде tar.gz архивов в ранее созданную директорию (к примеру /backup/20131121/), с именами в формате  dir-путьдодиректориибеззнаков'/'-годмесяцдень.час-минута-секунда.tar.gz.
6. Далее производится очистка от старых файлов и директорий (удаляются те файлы и директории, время модификации которых больше числа указанных дней (к примеру 30).
7. Далее производится синхронизация данных с помощью rsync между локальной директорией, в которой находятся все архивы и удаленной директорией, которая примонтированна к локальной директории.
8. После выполнения синхронизации производится размонтирование удаленной директории и закрытие программы.

Перед тем как приступать к работе:

- Установить rsync
- Установить необходимые пакеты, чтобы корректно срабатывала команда mount -t smbfs //ip/share...

Листинг скрипта:


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# PUBS - Python Universal Backup Script
# Created by Constantine in november 2013
# Mailto: myainetwork@gmail.com
# This script you can find on http://infdots.blogspot.com
# You can use this code under your own risk.

# Variables section
keepdays = '30'                              # How many time (in days) we must keep archives on local storage
addr = '192.168.0.1'                     # IP address of remote windows based server with share
port = '135'                                # Number of port on remote server to try check connection (netbios)
localdir4backups = '/backup/'               # Location of local storage where we will keep all backups
mountdir = '/winshare/'                   # Location of directory where we will mount remote windows share
winshare = 'docs'                   # Name of share on windows based server
winusername = 'administrator'                 # User name who have an access for windows share
winpassword = 'Fan09!%fdkjfd'                    # Password of windows user
workgroup = 'workroup'                           # Workgroup or domain name
backupfolder = ['/var/www/', '/opt/']       # Which directories we will archive to local backup storage
bases = ['joomla','feng','sold']    # Names of databases on local mysql server
mysqlhost = '127.0.0.1'                     # Address of mysql server
mysqlport = '3306'                          # Mysql port number
muser = 'root'                              # Mysql user name
mpass = 'superpuperpassword'                           # Mysql user password

# Importing of some modules
import socket
import sys
import subprocess
import os
import errno
import datetime
import string
import time

# Script vars
now = datetime.datetime.now()
storedir = localdir4backups+str(now.year)+str(now.month)+str(now.day)
ctime = str(now.year)+str(now.month)+str(now.day)+"."+str(now.hour)+"-"+str(now.minute)+"-"+str(now.second)

# Function for delete of old archives on local storage
def oldclear():
    try:
        starttime = time.time()
        oldout = subprocess.PIPE
        ocd = subprocess.Popen(["time find "+localdir4backups+" -type d -mtime +"+keepdays+" -exec rm -rf {} \;", "non existent"], shell=True, stdout=oldout, stderr=oldout)
        time.sleep(2.0)
        ocf = subprocess.Popen(["find "+localdir4backups+" -type f -mtime +"+keepdays+" -exec rm -rf {} \;", "non existent"], shell=True, stdout=oldout, stderr=oldout)
        time.sleep(2.0)
        output = ocd.poll()
        ocd.wait()
        ocf.wait()
        endtime = time.time()
        print (u'Estimated time is: ')
        print endtime - starttime
        print (u'')
    except:
        output = output
    return output


# Function for test port connection on remote backup server (Checking of SMB service is running)
def check_server(address, port):
        # Create a TCP socket
        s = socket.socket()
        print "Attempting to connect to %s on port %s" % (address, port)
        try:
                s.connect((address, port))
                print "Connected to %s on port %s" % (address, port)
                return True
        except socket.error, e:
                print "Connection to %s on port %s failed: %s" % (address, port, e)
                return False

# Function for syncing of local backup and remote
def sync():
    try:
        starttime = time.time()
        sout = subprocess.PIPE
        syncr = subprocess.Popen(["time rsync -avz --delete --stats "+localdir4backups+" "+mountdir, "non existent"], shell=True, stdout=sout, stderr=sout)
        time.sleep(2.0)
        output = syncr.poll()
        syncr.wait()
        endtime = time.time()
        print (u'Estimated time is: ')
        print endtime - starttime
        print (u'')
    except:
        output = output
    return output

# Function for mount remote share to local directory
def mountshare():
    try:
        starttime = time.time()
        loutput = subprocess.PIPE
        mnt = subprocess.Popen(["time mount -t smbfs //"+addr+"/"+winshare+" "+mountdir+" -o username="+winusername+",password="+winpassword+",workgroup="+workgroup, "non existent"], shell=True, stdout=loutput, stderr=loutput)
        time.sleep(2.0)
        output = mnt.poll()
        subprocess.Popen.kill(mnt)
        endtime = time.time()
        print (u'Estimated time is: ')
        print endtime - starttime
        print (u'')
    except:
        output = output
    return output

# Function for unmount remote directory
def unmount():
    try:
        starttime = time.time()
        unout = subprocess.PIPE
        umount = subprocess.Popen(["time umount "+mountdir, "non existent"], shell=True, stdout=unout, stderr=unout)
        time.sleep(2.0)
        output = umount.poll()
        umount.wait()
        endtime = time.time()
        print (u'Estimated time is: ')
        print endtime - starttime
        print (u'')
    except:
        output = output
    return output



# Function for creating folders in date format (Year:month:day) for local backups
def newdir():
    try:
        os.makedirs(storedir)
        result = 0
    except OSError:
        print 'Error can not create directory on local storage. Probably directory exist or you havent any privilegies for writing. Please check your permissions'
        result = 2
        if not os.path.isdir(storedir):
            raise
    except:
        result = 1
    return result


# Function TAR backup directories (such as /var/www etc.)
def tardir(backupfolder):
    clen = len(backupfolder)
    try:
        starttime = time.time()
        result = 0
        for bf in backupfolder:
            p = subprocess.Popen(["time tar -pczf "+storedir+"/"+"dir-"+bf.replace("/",'')+'-'+ctime+".tar.gz"+" "+bf+" > /dev/null 2>&1"], shell=True)
            time.sleep(2.0)
            p.wait()
        endtime = time.time()
        print (u'Estimated time is: ')
        print endtime - starttime
        print (u'')

    except OSError:
        print 'Error can not create archive. Probably file exist or you have not any privilegies for writing. Please check your permissions'
        result = 2
        if not os.path.isdir(storedir):
            raise
    except:
        result = 1
    return result


# Function for mysql backup
def mysql_backup(bases, user, passs, ocaldir4backups):
        try:
                starttime = time.time()
                for b in bases:
                        mb = subprocess.Popen(["time mysqldump -u "+user+" -p"+passs+" "+b+" | gzip > `date +"+storedir+"/"+"mysql-"+b+"-.sql.%Y%m%d.%H%M%S.gz`"], shell=True)
                time.sleep(2.0)
                mb.wait()
                endtime = time.time()
                print (u'Estimated time is: ')
                print endtime - starttime
                print (u'')
        except Exception as e:
                print ("Error with connection to database:")



if __name__ == '__main__':
        from optparse import OptionParser
        parser = OptionParser()

        parser.add_option("-a", "--address", dest="address", default=addr, help="ADDRESS for server", metavar="ADDRESS")

        parser.add_option("-p", "--port", dest="port", type="int", default=port, help="PORT for server", metavar="PORT")

        (options, args) = parser.parse_args()

        print ('')
        print ("Backup process launched at: "+ctime)
        print ('-----------------------------------------------------------------')
        check = check_server(options.address, options.port)

        print ('')

        check2 = check_server(mysqlhost, int(mysqlport))
        print ('')

        resret = check2+check

        print ('')

        if resret == 2:
            starttime = time.time()
            print ('Mysql working and remote backup server is accessible. Trying to mount remote share...')
            m = mountshare()
            if m == 0 or m == 32:
                    print ('Remote share mounted. Trying to create backups on local storage...')
                    ndr = newdir()
                    print ('Dump mysql databases...')
                    mysql_backup(bases, user=muser, passs=mpass, ocaldir4backups=localdir4backups)
                    print ('Backup directories...')
                    tardir(backupfolder)
                    print ("Backups has been made. Delete old archives, which older than "+keepdays+" days on local storage...")
                    odel = oldclear()
                    print ('Trying to sync...')
                    sn = sync()
                    print ('Unmount remote share...')
                    ut = unmount()
                    print ('DONE')
                    endtime = time.time()
                    print (u'Total time is (in minutes): ')
                    print (endtime - starttime)/60
                    print ('-----------------------------------------------------------------')
            else:
                    print ('Oops... I can not create archives on local storage and i can not sync')
                    print ('-----------------------------------------------------------------')


sys.exit()
Как запускать:

Ничего криминального в принципе нет - запихать в cron, если хотим регулярно его вызывать или же если хотим сами, то с команды скажем ./pubs-script.py... Вывод скрипта можно кстати перенаправить (скажем ./pubs-script.py >> /var/log/pubs.log).


P.S:
Перед тем как запустить скрипт, необходимо поправить переменные под Ваше хозяйство, которые расположены в самом начале программы после строчки # Variables section.

Что ещё можно сделать:

Возможно реализовать выгрузку данных на удалённый линуксовый сервер, необходимо поправить функцию и сделать право выбора (мол на какой тип сервера будем выгружать - линуксовый или виндушный).

Комментариев нет:

Отправить комментарий