Why is the Python script unreliable when run from rc.local on first boot?
Question: 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 
    # Randomizes and outputs to files the system root and mysql user passwords 
    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 
    # 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 = "" 
        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 
    


Answer: Doesn't `Popen` execute asynchronously?

It seems that during boot, the load is high and you are getting a race
condition between setting the root password and using it to set the next
password (next command).

Try

    
    
    p = Popen(['mysql', '-uroot', "--password=" + mrootpass, "-e", "UPDATE user SET Password = PASSWORD('" + mpass + "') WHERE User = '" + user + "';FLUSH PRIVILEGES;","mysql"])
    p.wait()
    

and see if that does it.

