Python script for MySQL Passwords Unreliable on first boot (rc.local)

C

cloudcontrol

The script below works great when logged in as root and run from the
command line, but when run at first boot using /etc/rc.local in Ubuntu
10.04, it fails about 25% of the time- the system root, mysql root and
some mysql user passwords are set correctly, but one will fail with
console log reporting standard mysql login error: "ERROR 1045 (28000):
Access denied for user 'root' @ 'localhost' (using password: YES)"

Is there something about running python scripts from init jobs that I
should account for, such as an environment variable?

#!/usr/bin/env python

# Udates system & MySQL root passwords on first boot
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'

import random, string
import crypt
import re
from subprocess import PIPE, Popen

def getsalt(chars = string.letters + string.digits):
# generate a random 2-character 'salt'
return random.choice(chars) + random.choice(chars)

def getpwd(chars = string.letters + string.digits, len = 12):
retval = "";
for i in range(0, len):
# generate 12 character alphanumeric password
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:
# Output file
handle = open(filename, 'w')
handle.write(hbuf)
handle.close()
except:
pass
#logh.write('failed to update ' + filename + "\n")
#logh.write('maybe you don\'t have permision to write to it?
\n')

logh = open(log, "a")
logh.write("Starting...\n")
# Generate passwords
pdict = {}
for user, placeholder in userpasswords.iteritems():
syspass = getpwd()
Popen(['usermod', '--password', crypt.crypt(syspass, getsalt()),
user])
logh.write(placeholder + ": User " + user + " --> " + syspass +
"\n")
pdict[placeholder] = syspass

# What's 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 = ""

Popen(['mysql', '-uroot', "--password=" + mrootpass, "-e", "UPDATE
user SET Password = PASSWORD('" + mpass + "') WHERE User = '" + user +
"';FLUSH PRIVILEGES;","mysql"])
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
 
T

Thomas Jollans

The script below works great when logged in as root and run from the
command line, but when run at first boot using /etc/rc.local in Ubuntu
10.04, it fails about 25% of the time- the system root, mysql root and
some mysql user passwords are set correctly, but one will fail with
console log reporting standard mysql login error: "ERROR 1045 (28000):
Access denied for user 'root' @ 'localhost' (using password: YES)"

It looks like MySQL itself isn't properly set up (yet) in those cases. But
why/how?

Ubuntu uses upstart to boot up. I don't know much about how this works, but I
understand it's dependency-based, and I expect it's parallel as well, where
possible. This means that different init scripts could run in a different
order sometimes, or even at the same time.

However, rc.local should really always be run last. It does not, by and of
itself, specify any dependencies, but it could require anything. It would be
ludicrous for Ubuntu to run rc.local before or at the same time as other
scripts, such as the MySQL one. The only plausible explanation for this
strange behaviour I can think of right now would be that either
a) Upstart/Ubuntu is just plain stupid, or
b) The MySQL init script spawns MySQL in the background and doesn't wait for
it to start up correctly. This seams highly unlikely and atypical of MySQL
init scripts, but maybe that's what's happening.
So this might be a bug in Ubuntu.

The way to fix this might simply be to detect the login error and retry, say,
5 times with 1-second intervals.
Is there something about running python scripts from init jobs that I
should account for, such as an environment variable?

#!/usr/bin/env python

# Udates system & MySQL root passwords on first boot
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'

import random, string
import crypt
import re
from subprocess import PIPE, Popen

def getsalt(chars = string.letters + string.digits):
# generate a random 2-character 'salt'
return random.choice(chars) + random.choice(chars)

def getpwd(chars = string.letters + string.digits, len = 12):
retval = "";
for i in range(0, len):
# generate 12 character alphanumeric password
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:
# Output file
handle = open(filename, 'w')
handle.write(hbuf)
handle.close()
except:
pass
#logh.write('failed to update ' + filename + "\n")
#logh.write('maybe you don\'t have permision to write to it?
\n')

logh = open(log, "a")
logh.write("Starting...\n")
# Generate passwords
pdict = {}
for user, placeholder in userpasswords.iteritems():
syspass = getpwd()
Popen(['usermod', '--password', crypt.crypt(syspass, getsalt()),
user])
logh.write(placeholder + ": User " + user + " --> " + syspass +
"\n")
pdict[placeholder] = syspass

# What's 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 = ""

Popen(['mysql', '-uroot', "--password=" + mrootpass, "-e", "UPDATE
user SET Password = PASSWORD('" + mpass + "') WHERE User = '" + user +
"';FLUSH PRIVILEGES;","mysql"])
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,962
Messages
2,570,134
Members
46,690
Latest member
MacGyver

Latest Threads

Top