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

Discussion in 'Python' started by cloudcontrol, Sep 13, 2010.

  1. cloudcontrol

    cloudcontrol Guest

    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
     
    cloudcontrol, Sep 13, 2010
    #1
    1. Advertising

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

    On Monday 13 September 2010, it occurred to cloudcontrol to exclaim:
    > 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
     
    Thomas Jollans, Sep 13, 2010
    #2
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Guest
    Replies:
    0
    Views:
    431
    Guest
    Nov 5, 2003
  2. krisk
    Replies:
    0
    Views:
    385
    krisk
    Feb 17, 2006
  3. ataraxia2500

    boot script

    ataraxia2500, Oct 19, 2003, in forum: Python
    Replies:
    3
    Views:
    361
    Paul Watson
    Oct 20, 2003
  4. dave
    Replies:
    4
    Views:
    1,419
    Steve Holden
    Nov 18, 2010
  5. Allen Marshall
    Replies:
    1
    Views:
    216
    Gunnar Hjalmarsson
    Jan 24, 2004
Loading...

Share This Page