在 Ubuntu 10.04 中,有一个 Python 脚本可以随机生成并输出系统根目录、MySQL 用户密码和其他密码到文件中。该脚本在作为 root 用户登录后从命令行运行时效果很好,但在使用 /etc/rc.local 在首次启动时运行时,大约有 25% 的几率失败。系统根目录、MySQL root 和一些 MySQL 用户密码会正确设置,但其中一个会失败,控制台日志报告标准 MySQL 登录错误:“ERROR 1045 (28000): Access denied for user ‘root’ @ ‘localhost’ (using password: YES)”。
2、解决方案
在尝试从 init 作业运行 Python 脚本时,需要考虑一些环境变量或其他因素。
-
在脚本中,使用 subprocess.Popen 函数来以异步方式执行子进程命令。这可能会导致在首次启动期间系统负载过高时发生竞争条件。
-
为了解决这个问题,可以将 Popen 函数的调用改为使用 wait() 方法等待子进程完成,确保在进行下一个操作之前,上一个操作已经完成。
-
脚本中还使用了 logh 变量来记录日志信息。但 logh 变量在脚本中声明为全局变量,但没有明确地对其进行初始化。应当在脚本的开头显式地初始化 logh 变量,以确保其能够正常工作。
修改后的脚本如下:
#!/usr/bin/env python
import random
import string
import crypt
import re
from subprocess import PIPE, Popen
def getsalt(chars=string.letters + string.digits):
return random.choice(chars) + random.choice(chars)
def getpwd(chars=string.letters + string.digits, length=12):
retval = ""
for i in range(0, length):
retval += random.choice(chars)
return retval
def replace_pass(filename):
handle = open(filename, 'r')
hbuf = handle.read()
handle.close()
for placeholder, password in pdict.iteritems():
hbuf = re.sub(placeholder, password, hbuf)
try:
handle = open(filename, 'w')
handle.write(hbuf)
handle.close()
except:
pass
files = ['/home/ubuntu/passwords', '/opt/data1/alfresco/extensions/extension/alfresco-global.properties', '/opt/data/etc/mysql/debian.cnf', '/home/ubuntu/duncil']
userpasswords = {'root': 'ROOTPASSWORD'}
mysqlpasswords = {'root': 'MYSQLPASSWORD', 'alfresco': 'alfrescoPASSWORD', 'debian-sys-maint': 'debian-sys-maintPASSWORD'}
otherpasswords = ['OTHERPASSWORD']
log = '/var/log/firstrun'
logh = open(log, "a")
logh.write("Starting...\n")
# Generate passwords
pdict = {}
for user, placeholder in userpasswords.iteritems():
syspass = getpwd()
process = Popen(['usermod', '--password', crypt.crypt(syspass, getsalt()), user])
process.wait()
logh.write(placeholder + ": User " + user + " --> " + syspass + "\n")
pdict[placeholder] = syspass
# Whats the MySQL Root password placeholder?
mplace = mysqlpasswords['root']
for user, placeholder in mysqlpasswords.iteritems():
mpass = getpwd()
if ("root" in mysqlpasswords) and (mysqlpasswords['root'] in pdict):
mrootpass = pdict[mysqlpasswords['root']]
else:
mrootpass = ""
process = Popen(['mysql', '-uroot', "--password=" + mrootpass, "-e", "UPDATE user SET Password = PASSWORD('" + mpass + "') WHERE User = '" + user + "';FLUSH PRIVILEGES;", "mysql"])
process.wait()
logh.write(placeholder + ": MySQL " + user + " --> " + mpass + "\n")
pdict[placeholder] = mpass
for placeholder in otherpasswords:
opass = getpwd()
logh.write(placeholder + ": " + opass + "\n")
pdict[placeholder] = opass
# Update passwords
for file in files:
logh.write("Replacing placeholders in " + file + "\n")
replace_pass(file)
logh.write("Finished\n")
logh.close()
经过修改后,脚本在首次启动时更可靠,问题得到解决。