db.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. #!/usr/bin/env python3
  2. # encoding: utf-8
  3. import os
  4. from shutil import copyfile
  5. from .cmd import run_bash_cmd
  6. from .utils import print_title
  7. PV_ARGS = 'pv --timer --rate --eta'
  8. MYSQL_BACKUP_ARGS = '--add-drop-database --add-drop-table --add-locks --single-transaction --quick '
  9. class DB():
  10. def __init__(self, config=None, database="", host='127.0.0.1', user='root', passwd=None, port=3306):
  11. import MySQLdb
  12. values = {
  13. 'db_port': 3306,
  14. 'db_host': '127.0.0.1',
  15. }
  16. if config:
  17. primary_master_config = getattr(config, 'primary_master_config', None)
  18. assert (primary_master_config)
  19. values.update(vars(primary_master_config))
  20. db = MySQLdb.connect(
  21. host=values['db_host'],
  22. user=values['db_user'],
  23. passwd=values['db_password'],
  24. db=database,
  25. charset='utf8',
  26. port=int(values['db_port']),
  27. )
  28. elif host:
  29. keys = ['host', 'user', 'passwd', 'db', 'charset', 'port']
  30. params = {'charset': 'utf8'}
  31. for key in keys:
  32. value = locals().get(key)
  33. if value:
  34. params[key] = value
  35. db = MySQLdb.connect(**params)
  36. assert db
  37. self.database = database
  38. self.cursor = db.cursor()
  39. def fetchone(self, sql):
  40. self.cursor.execute(sql)
  41. return self.cursor.fetchone()[0]
  42. def fetchall(self, sql):
  43. self.cursor.execute(sql)
  44. return self.cursor.fetchall()
  45. def get_databases(self, light=False):
  46. if self.database:
  47. return [self.database]
  48. ret = [i[0] for i in self.fetchall('show databases')]
  49. ret = sorted(list(set(ret) - set(['information_schema', 'mysql', 'performance_schema', 'test'])))
  50. if light == True:
  51. ret = sorted(list(set(ret) - set(['yunionmeter', 'yunionlogger'])))
  52. return ret
  53. def get_tables(self, exclude_prefix=''):
  54. ret = [i[0] for i in self.fetchall('show tables')]
  55. if not exclude_prefix:
  56. return ret
  57. else:
  58. return [i for i in ret if i.startswith(exclude_prefix)]
  59. def gen_export_args(self):
  60. ret = []
  61. for i in self.get_tables('opslog_tbl_') + self.get_tables('task'):
  62. ret.append('--ignore-table=%s.%s' % (self.database, i))
  63. return ' '.join(ret)
  64. def get_db_size(self, dbs=[], tables=[], ignores=''):
  65. sql = 'SELECT ROUND(SUM(data_length)) AS "size_bytes" FROM information_schema.TABLES'
  66. if dbs:
  67. db_name_str = ', '.join(['"%s"' % i for i in dbs])
  68. sql += ' where TABLE_SCHEMA in (%s)' % db_name_str
  69. if tables:
  70. db_name_str = ','.join(['"%s"' % i for i in tables])
  71. sql += ' and TABLE_NAME in (%s)' % db_name_str
  72. if ignores:
  73. ignores = ignores.replace('--ignore-table=', '').replace(' ', ' ')
  74. ignores = ignores.split(' ')
  75. ignores = ', '.join(['"%s"' % i for i in ignores if i])
  76. ignores = ' and CONCAT(TABLE_SCHEMA, ".", TABLE_NAME) not in (%s)' % ignores
  77. sql += ignores
  78. return int(self.fetchone(sql))
  79. def gen_db_config_args(config):
  80. values = {
  81. 'db_port': 3306,
  82. 'db_host': '127.0.0.1',
  83. }
  84. primary_master_config = getattr(config, 'primary_master_config', None)
  85. assert (primary_master_config)
  86. values.update(vars(primary_master_config))
  87. return ' -h "%(db_host)s" -u "%(db_user)s" -p"%(db_password)s" -P "%(db_port)s" ' % values
  88. def backup_db_table(config, db, table):
  89. fn = '%s.%s.sql' % (db, table)
  90. tgz = '%s.%s.sql.gz' % (db, table)
  91. _db = DB(config)
  92. db_size = _db.get_db_size([db], [table])
  93. db_args = gen_db_config_args(config)
  94. mysql_backup_args = MYSQL_BACKUP_ARGS
  95. cmd = 'mysqldump %(mysql_backup_args)s --databases %(db)s %(db_args)s --tables %(table)s ' % locals() # + ' --result-file ' + fn
  96. cmd += ' | %(PV_ARGS)s --name " Dumping %(name)s" --size %(db_size)s' % {
  97. 'PV_ARGS': PV_ARGS,
  98. 'db_size': db_size,
  99. 'name': db + '.' + table,
  100. }
  101. cmd += '| gzip -c > %(tgz)s' % locals()
  102. print('backup cmd: `%s`' % cmd)
  103. # run_bash_cmd(cmd)
  104. def backup_db(config, backup_path, light=False):
  105. print_title('back up db...')
  106. os.chdir(backup_path)
  107. ignores = ''
  108. dbs = DB(config)
  109. mysql_backup_args = MYSQL_BACKUP_ARGS
  110. if light is True:
  111. for dbname in dbs.get_databases(light):
  112. db = DB(config, dbname)
  113. ignores += ' ' + db.gen_export_args()
  114. db_name_str = ' '.join(dbs.get_databases(light))
  115. tgz = '%s/onecloud.sql.gz' % backup_path
  116. cmd = 'mysqldump %(mysql_backup_args)s --databases ' % locals() + db_name_str + ' ' \
  117. + gen_db_config_args(config) + ignores
  118. db_size = dbs.get_db_size(dbs.get_databases(), ignores=ignores)
  119. cmd += ' | %(PV_ARGS)s --name " Dumping Database" --size %(db_size)s' % {
  120. 'PV_ARGS': PV_ARGS,
  121. 'db_size': db_size,
  122. }
  123. cmd += ' | gzip -c > %s' % tgz
  124. run_bash_cmd(cmd)
  125. run_bash_cmd('ls -lah %s/*gz' % backup_path)
  126. def backup_config(src, dest):
  127. print_title('backing up the config')
  128. output = os.path.join(dest, 'config.yml')
  129. print('backup config %s to %s... ' % (src, output))
  130. run_bash_cmd('mkdir -p "%s"' % dest)
  131. copyfile(src, output)
  132. run_bash_cmd(""" sed -i -e 's@^ iso_install_mode: true@# iso_install_mode: true@' '%s' """ % output)