设为首页 收藏本站
查看: 322|回复: 0

[经验分享] Python 自动化管理Mysql数据库

[复制链接]

尚未签到

发表于 2018-8-3 11:15:13 | 显示全部楼层 |阅读模式
#!/usr/local/bin/python2.7  
#-*- coding:utf-8 -*-
  

  
from os import path
  
from optparse import OptionParser
  
from subprocess import PIPE, Popen
  
import MySQLdb
  
import glob
  
import os
  
import sys
  
import time
  
import datetime
  
import re
  

  

  
DIRNAME = path.dirname(__file__)
  
OPSTOOLS_DIR = path.abspath(path.join(DIRNAME, '..'))
  
sys.path.append(OPSTOOLS_DIR)
  
from library.mysql import MySQLDConfig, getMyVariables
  

  
REPLICATION_USER = 'repl'
  
REPLICATION_PASS = '123qwe'
  
MYSQL_DATA_DIR = '/home/david/data'
  
MYSQL_CONF_DIR = '/home/david/cnfs'
  
MYSQL_BACK_DIR = '/home/david/backup'
  

  
def opts():
  
    parser = OptionParser(usage="usage: %prog [options] arg1 arg2")
  
    parser.add_option("-c","--cmd",
  
        dest="cmd",
  
        action="store",
  
        default="check",
  
        help="Check the configuration file and database configuration parameters are different.[%options]"
  
    )
  
    parser.add_option("-n","--name",
  
        dest="name",
  
        action="store",
  
        default="mysqlinstance",
  
        help="Create Examples."
  
    )
  
    parser.add_option("-p","--port",
  
        dest="port",
  
        action="store",
  
        default="3306",
  
        help="Examples of port."
  
    )
  
    return parser.parse_args()
  

  
def checkPort(d, p):
  
    '''实例端口检测'''
  
    for m in d:
  
        if p == m.mysqld_vars['port']:
  
            return True
  
    return False
  

  
def setReplMaster(cur):
  
    '''设置slave数据库同步用户的授权'''
  
    sql = "GRANT REPLICATION SLAVE ON *.* TO %s@'localhost' IDENTIFIED BY '%s'" % (REPLICATION_USER, REPLICATION_PASS)
  
    cur.execute(sql)
  

  
def connMySQLd(mc):
  
    '''连接数据库'''
  
    host = '127.0.0.1'
  
    user = 'root'
  
    port = int(mc.mysqld_vars['port'])
  
    conn = MySQLdb.connect(host, port=port, user=user)
  
    cur = conn.cursor()
  
    return cur
  

  
def run_mysql(cnf):
  
    '''运行数据库'''
  
    cmd = "mysqld_safe --defaults-file=%s &" % cnf
  
    p = Popen(cmd, stdout=PIPE, shell=True)
  
    time.sleep(5)
  
    return p.returncode
  

  
def setOwner(p, user):
  
    '''设置目录权限'''
  
    os.system("chown -R %s:%s %s" % (user, user, p))
  

  
def mysql_install_db(cnf):
  
    '''数据库初始化'''
  
    p = Popen("mysql_install_db --defaults-file=%s" % cnf, stdout=PIPE, shell=True)
  
    #p = Popen("mysql_install_db --user=mysql --datadir=%s " % MYSQL_DATA_DIR, stdout=PIPE, shell=True)
  
    stdout, stderr = p.communicate()
  
    return p.returncode
  

  
def _genDict(name, port):
  
    '''设置文件存储目录及监听端口'''
  
    return {
  
        'pid-file': path.join(MYSQL_DATA_DIR, name, "%s.pid" % name),
  
        'socket': '/tmp/%s.sock' % name,
  
        'port': port,
  
        'datadir': path.join(MYSQL_DATA_DIR, name)+'/',
  
        'log_error': path.join(MYSQL_DATA_DIR, name)
  
    }
  

  
def readConfs():
  
    '''读取配置文件,如果配置文件不存在,使用默认配置生成配置文件'''
  
    confs = glob.glob(path.join(MYSQL_CONF_DIR, '*.cnf'))
  
    return [MySQLDConfig(c) for c in confs]
  

  
def getCNF(name):
  
    '''获取配置文件完整路径'''
  
    return path.join(MYSQL_CONF_DIR, "%s.cnf" % name)
  

  
def runMySQLdump(cmd):
  
    '''启动Mysql命令'''
  
    p = Popen(cmd, stdout=PIPE, shell=True)
  
    stdout, stderr = p.communicate()
  
    return p.returncode
  

  
def getBinlogPOS(f):
  
    '''获取binlog'''
  
    with open(f) as fd:
  
        f, p = findLogPos(l)
  
        if f and p:
  
            return f,p
  

  
def findLogPos(s):
  
    rlog = re.compile(r"MASTER_LOG_FILE='(\S+)',", re.IGNORECASE)
  
    rpos = re.compile(r"MASTER_LOG_POS=(\d+),?", re.IGNORECASE)
  
    log = rlog.search(s)
  
    pos = rpos.search(s)
  
    if log and pos:
  
        return log.group(1), int(pos.group(1))
  
    else:
  
        return (None, None)
  

  
def changeMaster(cur, host, port, user, mpass, mf, p):
  
    sql = '''CHANGE MASTER TO
  
        MASTER_HOST='%s',
  
        MASTER_PORT='%s',
  
        MASTER_USER='%s',
  
        MASTER_PASSWORD='%s',
  
        MASTER_LOG_FILE='%s',
  
        MASTER_LOG_POS=%s;''' % (host, port, user, mpass, mf, p)
  
        cur.execute(sql)
  

  
def createInstance(name, port, dbtype="master", **kw):
  
    '''创建数据库实例'''
  
    cnf = path.join(MYSQL_CONF_DIR, "%s.cnf" % name)
  
    datadir = path.join(MYSQL_DATA_DIR, name)
  
    exists_cnfs = readConfs()
  

  
    if checkPort(exists_cnfs, port):
  
        print >> sys.stderr, "port exist."
  
        sys.exit(-1)
  
    if not path.exists(cnf):
  
        c = _genDict(name, port)
  
        c.update(kw)
  
        mc = MySQLDConfig(cnf, **c)
  
        mc.save()
  
    else:
  
        mc = MySQLDConfig(cnf, **kw)
  

  
    if not path.exists(datadir):
  
        mysql_install_db(cnf)
  
        setOwner(datadir, mc.mysqld_vars['user'])
  
        run_mysql(cnf)
  
        time.sleep(3)
  
        cur = connMySQLd(mc)
  
        setReplMaster(cur)
  

  
def diffVariables(instance_name):
  
    '''查询数据库配置文件和数据库配置的差异'''
  
    cnf = getCNF(instance_name)
  
    if path.exists(cnf):
  
        mc = MySQLDConfig(cnf)
  
        print mc
  
        cur = connMySQLd(mc)
  
        vars = getMyVariables(cur)
  
        for k, v in mc.mysqld_vars.items():
  
            k = k.replace('-', '_')
  
            if k in vars and vars[k] != v:
  
                print k, v, vars[k]
  

  
def setVariable(instance_name, variable, value):
  
    '''重新加载配置'''
  
    cnf = getCNF(instance_name)
  
    if path.exists(cnf):
  
        mc = MySQLDConfig(cnf)
  
        cur = connMySQLd(mc)
  
        cur.execute('set global %s = %s' % (variable, value))
  
        mc.set_var(variable, value)
  
        mc.save()
  

  
def backupMySQL(instance_name):
  
    '''备份数据库'''
  
    cnf = getCNF(instance_name)
  
    if path.exists(cnf):
  
        mc = MySQLDConfig(cnf)
  
    now = datetime.datetime.now()
  
    timestamp = now.strftime('%Y-%m-%d-%H%M%S')
  
    backup_file = path.join(MYSQL_BACK_DIR, instance_name, timestamp+'.sql')
  
    _dir = path.dirname(backup_file)
  
    if not path.exists(_dir):
  
        os.makedirs(_dir)
  
    cmd = 'mysqldump -A -x -F --master-data=1 --host=127.0.0.1 --user=root --port=%s > %s' % (mc.mysqld_vars['port'], backup_file)
  
    runMySQLdump(cmd)
  

  
def restoreMySQL(instance_name, instance_port, sqlfile, **kw):
  
    createInstance(instance_name, instance_port, **kw)
  
    cnf = getCNF(instance_name)
  
    if path.exists(cnf):
  
        mc = MySQLDConfig(cnf)
  
        cur = connMySQLd(mc)
  
        cmd = "mysql -h 127.0.0.1 -P %s -u root < %s" % (mc.mysqld_vars['port'], sqlfile)
  
        f, p = getBinlogPOS(sqlfile)
  
        runMySQLdump(cmd)
  
        changeMaster(cur,
  
                     host=kw['master-host'],
  
                     port=kw['master-port'],
  
                     user=REPLICATION_USER,
  
                     mpass=REPLICATION_PASS,
  
                     mf=f,
  
                     p=p)
  

  
def _init():
  
    '''查询mysql几个目录是否存在,如果不存在,自动创建'''
  
    if not path.exists(MYSQL_DATA_DIR):
  
        os.makedirs(MYSQL_DATA_DIR)
  
    if not path.exists(MYSQL_CONF_DIR):
  
        os.makedirs(MYSQL_CONF_DIR)
  
    if not path.exists(MYSQL_BACK_DIR):
  
        os.makedirs(MYSQL_BACK_DIR)
  

  
def main():
  
    opt, args = opts()
  
    instance_name = opt.name
  
    instance_port = opt.port
  
    command = opt.cmd
  
    if command == "create":
  
        if not args:
  
            createInstance(instance_name, instance_port)
  
        else:
  
            dbtype = args[0]
  
            serverid = args[1]
  
            mysqld_options = {'server-id':serverid}
  
            if dbtype == 'master':
  
                mysqld_options['log-bin'] = 'mysql-bin'
  
            elif dbtype == 'slave':
  
                master_host = args[2]
  
                master_port = args[3]
  
                mysqld_options['master-host'] = master_host
  
                mysqld_options['master-port'] = master_port
  
                mysqld_options['master-user'] = REPLICATION_USER
  
                mysqld_options['master-password'] = REPLICATION_PASS
  
                mysqld_options['skip-slave-start'] = None
  
                mysqld_options['replicate-ignore-db'] = 'mysql'
  
                mysqld_options['read-only'] = None
  
            createInstance(instance_name, instance_port, dbtype=dbtype, **mysqld_options)
  
    elif command == 'check':
  
        diffVariables(instance_name)
  
    elif command == 'adjust':
  
        variable = args[0]
  
        value = args[1]
  
        setVariable(instance_name, variable, value)
  
    elif command == 'backup':
  
        backupMySQL(instance_name)
  
    elif command == 'restore':
  
        serverid == args[0]
  
        mhost = args[1]
  
        mport = args[2]
  
        sqlfile = args[3]
  
        mysqld_options = {
  
            "master-host":mhost,
  
            "master-port":mport,
  
            "server-id":serverid,
  
            "skip-slave-start":None,
  
        }
  
        restoreMySQL(instance_name, instance_port, sqlfile, **mysqld_options)
  

  
if __name__ == "__main__":
  
    print main()

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-545834-1-1.html 上篇帖子: 使用python实现统计Nginx进程所占用的物理内存 下篇帖子: python调用zabbix api接口实时展示数据
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表