import subprocess, shlex import install import time class mysqlUtilities: @staticmethod def createDatabase(dbname, dbuser, dbpassword, publicip): """ Create database and user with improved error handling and validation """ import logging # Validate input parameters if not dbname or not dbuser or not dbpassword: logging.InstallLog.writeToFile(f"ERROR: Missing required parameters - dbname: {dbname}, dbuser: {dbuser}, password: {'SET' if dbpassword else 'EMPTY'}") return 0 logging.InstallLog.writeToFile(f"Creating database '{dbname}' and user '{dbuser}' with password length: {len(dbpassword)}") try: # Step 1: Create database createDB = "CREATE DATABASE IF NOT EXISTS " + dbname try: from json import loads mysqlData = loads(open("/etc/cyberpanel/mysqlPassword", 'r').read()) initCommand = 'mariadb -h %s --port %s -u %s -p%s -e "' % (mysqlData['mysqlhost'], mysqlData['mysqlport'], mysqlData['mysqluser'], mysqlData['mysqlpassword']) remote = 1 logging.InstallLog.writeToFile("Using remote MySQL configuration") except: passFile = "/etc/cyberpanel/mysqlPassword" f = open(passFile) data = f.read() password = data.split('\n', 1)[0] initCommand = 'mariadb -u root -p' + password + ' -e "' remote = 0 logging.InstallLog.writeToFile("Using local MySQL configuration") command = initCommand + createDB + '"' logging.InstallLog.writeToFile(f"Executing database creation: CREATE DATABASE IF NOT EXISTS {dbname}") if install.preFlightsChecks.debug: print(command) time.sleep(10) cmd = shlex.split(command) res = subprocess.call(cmd) if res != 0: logging.InstallLog.writeToFile(f"ERROR: Database creation failed with return code: {res}") return 0 else: logging.InstallLog.writeToFile(f"✓ Database '{dbname}' created successfully") # Step 2: Create user (drop first if exists to avoid conflicts) if remote: dropUser = f"DROP USER IF EXISTS '{dbuser}'@'{publicip}'" createUser = f"CREATE USER '{dbuser}'@'{publicip}' IDENTIFIED BY '{dbpassword}'" host = publicip else: dropUser = f"DROP USER IF EXISTS '{dbuser}'@'localhost'" createUser = f"CREATE USER '{dbuser}'@'localhost' IDENTIFIED BY '{dbpassword}'" host = 'localhost' # Drop user if exists command = initCommand + dropUser + '"' logging.InstallLog.writeToFile(f"Dropping existing user '{dbuser}'@'{host}' if exists") if install.preFlightsChecks.debug: print(command) time.sleep(10) cmd = shlex.split(command) subprocess.call(cmd) # Ignore return code for DROP USER IF EXISTS # Create user command = initCommand + createUser + '"' logging.InstallLog.writeToFile(f"Creating user '{dbuser}'@'{host}' with password") if install.preFlightsChecks.debug: print(command) time.sleep(10) cmd = shlex.split(command) res = subprocess.call(cmd) if res != 0: logging.InstallLog.writeToFile(f"ERROR: User creation failed with return code: {res}") return 0 else: logging.InstallLog.writeToFile(f"✓ User '{dbuser}'@'{host}' created successfully") # Step 3: Handle special cases and grant privileges if remote: ### DigitalOcean MySQL compatibility if mysqlData['mysqlhost'].find('ondigitalocean') > -1: alterUserPassword = f"ALTER USER '{dbuser}'@'{publicip}' IDENTIFIED WITH mysql_native_password BY '{dbpassword}'" command = initCommand + alterUserPassword + '"' logging.InstallLog.writeToFile(f"Applying DigitalOcean MySQL compatibility for '{dbuser}'@'{publicip}'") if install.preFlightsChecks.debug: print(command) time.sleep(10) cmd = shlex.split(command) res = subprocess.call(cmd) if res != 0: logging.InstallLog.writeToFile(f"WARNING: DigitalOcean ALTER USER failed with return code: {res}") ## RDS vs Standard MySQL permissions if mysqlData['mysqlhost'].find('rds.amazon') == -1: grantPrivileges = f"GRANT ALL PRIVILEGES ON {dbname}.* TO '{dbuser}'@'{publicip}'" else: grantPrivileges = f"GRANT INDEX, DROP, UPDATE, ALTER, CREATE, SELECT, INSERT, DELETE ON {dbname}.* TO '{dbuser}'@'{publicip}'" host = publicip else: grantPrivileges = f"GRANT ALL PRIVILEGES ON {dbname}.* TO '{dbuser}'@'localhost'" host = 'localhost' # Grant privileges command = initCommand + grantPrivileges + '"' logging.InstallLog.writeToFile(f"Granting privileges on database '{dbname}' to user '{dbuser}'@'{host}'") if install.preFlightsChecks.debug: print(command) time.sleep(10) cmd = shlex.split(command) res = subprocess.call(cmd) if res != 0: logging.InstallLog.writeToFile(f"ERROR: Grant privileges failed with return code: {res}") return 0 else: logging.InstallLog.writeToFile(f"✓ Privileges granted successfully") # Step 4: Flush privileges flushCommand = initCommand + "FLUSH PRIVILEGES" + '"' logging.InstallLog.writeToFile("Flushing MySQL privileges") cmd = shlex.split(flushCommand) res = subprocess.call(cmd) if res != 0: logging.InstallLog.writeToFile(f"WARNING: FLUSH PRIVILEGES failed with return code: {res}") else: logging.InstallLog.writeToFile("✓ Privileges flushed successfully") logging.InstallLog.writeToFile(f"✅ Database '{dbname}' and user '{dbuser}' created successfully!") return 1 except BaseException as msg: logging.InstallLog.writeToFile(f"❌ CRITICAL ERROR in createDatabase: {str(msg)}") import traceback logging.InstallLog.writeToFile(f"Full traceback: {traceback.format_exc()}") return 0