bug fix: create proper backups incase of multiple database users

This commit is contained in:
Usman Nasir
2021-04-11 22:58:22 +05:00
parent 8ce49c303d
commit c83eb3ab6c
5 changed files with 136 additions and 81 deletions

View File

@@ -1,5 +1,3 @@
from django.db import models from django.db import models
class DBUsers(models.Model): class DBUsers(models.Model):

View File

@@ -13,7 +13,7 @@ from firewall.models import FirewallRules
from plogical.firewallUtilities import FirewallUtilities from plogical.firewallUtilities import FirewallUtilities
from plogical.processUtilities import ProcessUtilities from plogical.processUtilities import ProcessUtilities
from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
from plogical.mysqlUtilities import mysqlUtilities
class ClusterManager: class ClusterManager:
LogURL = "https://cloud.cyberpanel.net/HighAvailability/RecvData" LogURL = "https://cloud.cyberpanel.net/HighAvailability/RecvData"
@@ -34,7 +34,7 @@ class ClusterManager:
try: try:
finalData = {'name': self.config['name'], 'type': self.type, 'message': message, 'token': self.config['token']} finalData = {'name': self.config['name'], 'type': self.type, 'message': message, 'token': self.config['token']}
resp = requests.post(ClusterManager.LogURL, data=json.dumps(finalData), verify=False) resp = requests.post(ClusterManager.LogURL, data=json.dumps(finalData), verify=False)
logging.writeToFile(resp.text + '[info]') # logging.writeToFile(resp.text + '[info]')
except BaseException as msg: except BaseException as msg:
logging.writeToFile('%s. [31:404]' % (str(msg))) logging.writeToFile('%s. [31:404]' % (str(msg)))
@@ -253,6 +253,12 @@ password=%s""" % (rootdbpassword, rootdbpassword)
writeToFile.write(content) writeToFile.write(content)
writeToFile.close() writeToFile.close()
## Let this server process updates if master is down
connection, cursor = mysqlUtilities.setupConnection()
cursor.execute("SET GLOBAL wsrep_provider_options='pc.ignore_sb=TRUE'")
connection.close()
self.PostStatus('Fail over server successfully booted. [200]') self.PostStatus('Fail over server successfully booted. [200]')
### ###

View File

@@ -1,7 +1,5 @@
import os, sys import os, sys
from s3transfer import TransferConfig
sys.path.append('/usr/local/CyberCP') sys.path.append('/usr/local/CyberCP')
import django import django
@@ -10,6 +8,8 @@ try:
django.setup() django.setup()
except: except:
pass pass
import pexpect import pexpect
from plogical import CyberCPLogFileWriter as logging from plogical import CyberCPLogFileWriter as logging
import subprocess import subprocess
@@ -34,7 +34,6 @@ from xml.etree import ElementTree
from xml.dom import minidom from xml.dom import minidom
import time import time
from shutil import copy from shutil import copy
from distutils.dir_util import copy_tree
from random import randint from random import randint
from plogical.processUtilities import ProcessUtilities from plogical.processUtilities import ProcessUtilities
@@ -71,6 +70,8 @@ class backupUtilities:
def prepareBackupMeta(backupDomain, backupName, tempStoragePath, backupPath): def prepareBackupMeta(backupDomain, backupName, tempStoragePath, backupPath):
try: try:
connection, cursor = mysqlUtilities.mysqlUtilities.setupConnection()
status = os.path.join(backupPath, 'status') status = os.path.join(backupPath, 'status')
logging.CyberCPLogFileWriter.statusWriter(status, 'Setting up meta data..') logging.CyberCPLogFileWriter.statusWriter(status, 'Setting up meta data..')
@@ -170,50 +171,31 @@ class backupUtilities:
databasesXML = Element('Databases') databasesXML = Element('Databases')
for items in databases: for items in databases:
try:
dbuser = DBUsers.objects.get(user=items.dbUser)
userToTry = items.dbUser
except:
try:
dbusers = DBUsers.objects.all().filter(user=items.dbUser)
userToTry = items.dbUser
for it in dbusers:
dbuser = it
break
userToTry = mysqlUtilities.mysqlUtilities.fetchuser(items.dbName)
if userToTry == 0 or userToTry == 1:
continue
try:
dbuser = DBUsers.objects.get(user=userToTry)
except:
try:
dbusers = DBUsers.objects.all().filter(user=userToTry)
for it in dbusers:
dbuser = it
break
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(
'While creating backup for %s, we failed to backup database %s. Error message: %s' % (
backupDomain, items.dbName, str(msg)))
continue
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(
'While creating backup for %s, we failed to backup database %s. Error message: %s' % (
backupDomain, items.dbName, str(msg)))
continue
databaseXML = Element('database') databaseXML = Element('database')
child = SubElement(databaseXML, 'dbName') child = SubElement(databaseXML, 'dbName')
child.text = str(items.dbName) child.text = str(items.dbName)
child = SubElement(databaseXML, 'dbUser')
child.text = str(userToTry) cursor.execute("select user,host from mysql.db where db='%s'" % (items.dbName))
child = SubElement(databaseXML, 'password') databaseUsers = cursor.fetchall()
child.text = str(dbuser.password)
for databaseUser in databaseUsers:
databaseUserXML = Element('databaseUsers')
child = SubElement(databaseUserXML, 'dbUser')
child.text = databaseUser[0]
child = SubElement(databaseUserXML, 'dbHost')
child.text = databaseUser[1]
## Fetch user password
dbuser = DBUsers.objects.get(user=databaseUser[0])
child = SubElement(databaseUserXML, 'password')
child.text = str(dbuser.password)
databaseXML.append(databaseUserXML)
databasesXML.append(databaseXML) databasesXML.append(databaseXML)
@@ -232,7 +214,6 @@ class backupUtilities:
child.text = items child.text = items
metaFileXML.append(aliasesXML) metaFileXML.append(aliasesXML)
except BaseException as msg: except BaseException as msg:
logging.CyberCPLogFileWriter.statusWriter(status, '%s. [167:prepMeta]' % (str(msg))) logging.CyberCPLogFileWriter.statusWriter(status, '%s. [167:prepMeta]' % (str(msg)))
@@ -260,7 +241,6 @@ class backupUtilities:
dnsRecordsXML.append(dnsRecordXML) dnsRecordsXML.append(dnsRecordXML)
metaFileXML.append(dnsRecordsXML) metaFileXML.append(dnsRecordsXML)
except BaseException as msg: except BaseException as msg:
logging.CyberCPLogFileWriter.statusWriter(status, '%s. [158:prepMeta]' % (str(msg))) logging.CyberCPLogFileWriter.statusWriter(status, '%s. [158:prepMeta]' % (str(msg)))
@@ -316,6 +296,7 @@ class backupUtilities:
except BaseException as msg: except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile("%s [207][5009]" % (str(msg)))
logging.CyberCPLogFileWriter.statusWriter(status, "%s [207][5009]" % (str(msg))) logging.CyberCPLogFileWriter.statusWriter(status, "%s [207][5009]" % (str(msg)))
return 0, str(msg) return 0, str(msg)
@@ -562,6 +543,8 @@ class backupUtilities:
domain = backupMetaData.find('masterDomain').text domain = backupMetaData.find('masterDomain').text
phpSelection = backupMetaData.find('phpSelection').text phpSelection = backupMetaData.find('phpSelection').text
externalApp = backupMetaData.find('externalApp').text externalApp = backupMetaData.find('externalApp').text
VERSION = backupMetaData.find('VERSION').text
BUILD = backupMetaData.find('BUILD').text
### Fetch user details ### Fetch user details
@@ -619,14 +602,35 @@ class backupUtilities:
website = Websites.objects.get(domain=domain) website = Websites.objects.get(domain=domain)
for database in databases: for database in databases:
dbName = database.find('dbName').text dbName = database.find('dbName').text
dbUser = database.find('dbUser').text
if mysqlUtilities.mysqlUtilities.createDatabase(dbName, dbUser, "cyberpanel") == 0: if VERSION == '2.1' and BUILD == '1':
raise BaseException("Failed to create Databases!") first = 1
newDB = Databases(website=website, dbName=dbName, dbUser=dbUser) databaseUsers = database.findall('databaseUsers')
newDB.save()
for databaseUser in databaseUsers:
dbUser = databaseUser.find('dbUser').text
if first:
if mysqlUtilities.mysqlUtilities.createDatabase(dbName, dbUser, "cyberpanel") == 0:
raise BaseException("Failed to create Databases!")
newDB = Databases(website=website, dbName=dbName, dbUser=dbUser)
newDB.save()
first = 0
else:
dbUser = database.find('dbUser').text
if mysqlUtilities.mysqlUtilities.createDatabase(dbName, dbUser, "cyberpanel") == 0:
raise BaseException("Failed to create Databases!")
newDB = Databases(website=website, dbName=dbName, dbUser=dbUser)
newDB.save()
## Create dns zone ## Create dns zone
@@ -692,6 +696,8 @@ class backupUtilities:
## extracting master domain for later use ## extracting master domain for later use
backupMetaData = ElementTree.parse(os.path.join(completPath, "meta.xml")) backupMetaData = ElementTree.parse(os.path.join(completPath, "meta.xml"))
masterDomain = backupMetaData.find('masterDomain').text masterDomain = backupMetaData.find('masterDomain').text
VERSION = backupMetaData.find('VERSION').text
BUILD = backupMetaData.find('BUILD').text
twoPointO = 0 twoPointO = 0
try: try:
@@ -854,10 +860,31 @@ class backupUtilities:
databases = backupMetaData.findall('Databases/database') databases = backupMetaData.findall('Databases/database')
for database in databases: for database in databases:
dbName = database.find('dbName').text dbName = database.find('dbName').text
password = database.find('password').text
if mysqlUtilities.mysqlUtilities.restoreDatabaseBackup(dbName, completPath, password) == 0: if VERSION == '2.1' and BUILD == '1':
raise BaseException first = 1
databaseUsers = database.findall('databaseUsers')
for databaseUser in databaseUsers:
dbUser = databaseUser.find('dbUser').text
dbHost = databaseUser.find('dbHost').text
password = databaseUser.find('password').text
if first:
first = 0
if mysqlUtilities.mysqlUtilities.restoreDatabaseBackup(dbName, completPath, password, 1) == 0:
raise BaseException
mysqlUtilities.mysqlUtilities.createDatabase(dbName, dbUser, password, 0, dbHost)
else:
password = database.find('password').text
if mysqlUtilities.mysqlUtilities.restoreDatabaseBackup(dbName, completPath, password) == 0:
raise BaseException
## Databases restored ## Databases restored

View File

@@ -41,7 +41,7 @@ class DNS:
self.status = data[2].rstrip('\n') self.status = data[2].rstrip('\n')
return 1 return 1
else: else:
logging.CyberCPLogFileWriter.writeToFile('User %s does not have CloudFlare configured.' % (self.admin.userName)) #logging.CyberCPLogFileWriter.writeToFile('User %s does not have CloudFlare configured.' % (self.admin.userName))
return 0 return 0
def cfTemplate(self, zoneDomain, admin, enableCheck=None): def cfTemplate(self, zoneDomain, admin, enableCheck=None):
@@ -711,26 +711,30 @@ class DNS:
## Add Record to CF if SYNC Enabled ## Add Record to CF if SYNC Enabled
dns = DNS() try:
dns.admin = zone.admin
dns.loadCFKeys()
cf = CloudFlare.CloudFlare(email=dns.email, token=dns.key) dns = DNS()
dns.admin = zone.admin
dns.loadCFKeys()
if dns.status == 'Enable': cf = CloudFlare.CloudFlare(email=dns.email, token=dns.key)
try:
params = {'name': zone.name, 'per_page': 50}
zones = cf.zones.get(params=params)
for zone in sorted(zones, key=lambda v: v['name']): if dns.status == 'Enable':
zone = zone['id'] try:
params = {'name': zone.name, 'per_page': 50}
zones = cf.zones.get(params=params)
DNS.createDNSRecordCloudFlare(cf, zone, name, type, value, ttl, priority) for zone in sorted(zones, key=lambda v: v['name']):
zone = zone['id']
except CloudFlare.exceptions.CloudFlareAPIError as e: DNS.createDNSRecordCloudFlare(cf, zone, name, type, value, ttl, priority)
logging.CyberCPLogFileWriter.writeToFile(str(e))
except Exception as e: except CloudFlare.exceptions.CloudFlareAPIError as e:
logging.CyberCPLogFileWriter.writeToFile(str(e)) logging.CyberCPLogFileWriter.writeToFile(str(e))
except Exception as e:
logging.CyberCPLogFileWriter.writeToFile(str(e))
except:
pass
except BaseException as msg: except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [createDNSRecord]") logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [createDNSRecord]")

View File

@@ -107,22 +107,33 @@ class mysqlUtilities:
return 0, 0 return 0, 0
@staticmethod @staticmethod
def createDatabase(dbname,dbuser,dbpassword): def createDatabase(dbname,dbuser,dbpassword, dbcreate = 1, host = None):
try: try:
if dbcreate:
HostToUse = mysqlUtilities.LOCALHOST
else:
HostToUse = host
connection, cursor = mysqlUtilities.setupConnection() connection, cursor = mysqlUtilities.setupConnection()
if connection == 0: if connection == 0:
return 0 return 0
cursor.execute("CREATE DATABASE " + dbname)
## Create db
if dbcreate:
cursor.execute("CREATE DATABASE " + dbname)
## create user
if mysqlUtilities.REMOTEHOST.find('ondigitalocean') > -1: if mysqlUtilities.REMOTEHOST.find('ondigitalocean') > -1:
query = "CREATE USER '%s'@'%s' IDENTIFIED WITH mysql_native_password BY '%s'" % ( query = "CREATE USER '%s'@'%s' IDENTIFIED WITH mysql_native_password BY '%s'" % (
dbuser, mysqlUtilities.LOCALHOST, dbpassword) dbuser, HostToUse, dbpassword)
else: else:
query = "CREATE USER '" + dbuser + "'@'%s' IDENTIFIED BY '" % ( query = "CREATE USER '" + dbuser + "'@'%s' IDENTIFIED BY '" % (
mysqlUtilities.LOCALHOST) + dbpassword + "'" HostToUse) + dbpassword + "'"
if os.path.exists(ProcessUtilities.debugPath): if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile(query) logging.CyberCPLogFileWriter.writeToFile(query)
@@ -130,14 +141,15 @@ class mysqlUtilities:
cursor.execute(query) cursor.execute(query)
if mysqlUtilities.RDS == 0: if mysqlUtilities.RDS == 0:
cursor.execute("GRANT ALL PRIVILEGES ON " + dbname + ".* TO '" + dbuser + "'@'%s'" % (mysqlUtilities.LOCALHOST)) cursor.execute("GRANT ALL PRIVILEGES ON " + dbname + ".* TO '" + dbuser + "'@'%s'" % (HostToUse))
if os.path.exists(ProcessUtilities.debugPath): if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile("GRANT ALL PRIVILEGES ON " + dbname + ".* TO '" + dbuser + "'@'%s'" % (mysqlUtilities.LOCALHOST)) logging.CyberCPLogFileWriter.writeToFile("GRANT ALL PRIVILEGES ON " + dbname + ".* TO '" + dbuser + "'@'%s'" % (HostToUse))
else: else:
cursor.execute( cursor.execute(
"GRANT INDEX, DROP, UPDATE, ALTER, CREATE, SELECT, INSERT, DELETE ON " + dbname + ".* TO '" + dbuser + "'@'%s'" % (mysqlUtilities.LOCALHOST)) "GRANT INDEX, DROP, UPDATE, ALTER, CREATE, SELECT, INSERT, DELETE ON " + dbname + ".* TO '" + dbuser + "'@'%s'" % (HostToUse))
if os.path.exists(ProcessUtilities.debugPath): if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile("GRANT INDEX, DROP, UPDATE, ALTER, CREATE, SELECT, INSERT, DELETE ON " + dbname + ".* TO '" + dbuser + "'@'%s'" % (mysqlUtilities.LOCALHOST)) logging.CyberCPLogFileWriter.writeToFile("GRANT INDEX, DROP, UPDATE, ALTER, CREATE, SELECT, INSERT, DELETE ON " + dbname + ".* TO '" + dbuser + "'@'%s'" % (HostToUse))
connection.close() connection.close()
return 1 return 1
@@ -207,7 +219,14 @@ class mysqlUtilities:
return 0 return 0
cursor.execute("DROP DATABASE `%s`" % (dbname)) cursor.execute("DROP DATABASE `%s`" % (dbname))
cursor.execute("DROP USER '"+dbuser+"'@'%s'" % (mysqlUtilities.LOCALHOST))
## Try deleting all user who had priviliges on db
cursor.execute("select user,host from mysql.db where db='%s'" % (dbname))
databaseUsers = cursor.fetchall()
for databaseUser in databaseUsers:
cursor.execute("DROP USER '"+databaseUser[0]+"'@'%s'" % (databaseUser[1]))
connection.close() connection.close()
return 1 return 1
@@ -337,6 +356,7 @@ password=%s
return 0 return 0
if passwordCheck == None: if passwordCheck == None:
connection, cursor = mysqlUtilities.setupConnection() connection, cursor = mysqlUtilities.setupConnection()
if connection == 0: if connection == 0: