I have a Python script, let's say install.py
(which I am running as sudo), on OS X that installs homebrew, Xcode, pip, ruby, swig, and, ultimately, salt. The problem is that running and installing everything (Xcode CLI in partituclar) takes so long to run, that sudo times out, requiring another prompt for admin credentials.
Here's the thing. As part of install.py
, before kicking off all the installations, I first create a local admin user by opening a subprocess and use:
make_admin_account = {
"mkdir -p /Users/%(accountname)s",
"sudo dscl . -create /Users/%(accountname)s",
"sudo dscl . -create /Users/%(accountname)s UserShell /bin/bash",
"sudo dscl . -create /Users/%(accountname)s RealName \"%(fullname)s\"",
"sudo dscl . -create /Users/%(accountname)s UniqueID \"%(uid)s\"",
"sudo dscl . -create /Users/%(accountname)s PrimaryGroupID 80",
"sudo dscl . -create /Users/%(accountname)s NFSHomeDirectory /Users/%(accountname)s",
"sudo dscl . -passwd /Users/%(accountname)s \"%(password)s\"",
"sudo dscl . -append /Groups/admin GroupMembership%(accountname)s",
"sudo dscl . -append /Groups/_appserveradm GroupMembership %(accountname)s",
"sudo dscl . -append /Groups/_appserverusr GroupMembership %(accountname)s",
"sudo chown -R %(accountname)s /Users/%(accountname)s",
"sudo createhomedir -c -u %(accountname)s"
}
So, now we have a local admin account. Pretty simply now, run through each of the installers. Let's jump ahead to where Xcode CLI had been installed, now we're kicking off homebrew:
print("Install Homebrew")
execute("sudo -H -u %s ruby homebrew_ruby" % accountname)
(execute()
is just a simple function that's calling subprocess.Popen()
) As soon as it encounters sudo
, it wants admin credentials again. This is not desired behavior. So, how about passing a preexec_fn
to the subprocess and running as the newly created admin account?
def demote(user_uid, user_gid):
def result():
os.setgid(user_gid)
os.getuid(user_uid)
return result
preexec_fn = demote(pwd.getpwnam(accountname).pw_uid, pwd.getpwnam(accountname).pw_gid)
execute("ruby homebrew_ruby", preexec_fn=preexec_fn)
Again, execute
is just taking the preexec_fn
argument and passing it to subprocess.Popen
. What's returned is:
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Permission denied
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Permission denied
chdir: error retrieving current directory: getcwd: cannot access parent directories: Permission denied
chdir: error retrieving current directory: getcwd: cannot access parent directories: Permission denied
job-working-directory: error retrieving current directory: getcwd: cannot access parent directories: Permission denied
At this point, I'm thinking my new admin account is setup incorrectly. Exit script, and try su'ing to the new admin account I had just created:
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Permission denied
Looks familiar.
So, to put my desire into a sentence: I'm looking for a way to keep a long Python script from prompting for admin creds after it times out in the default 5 minutes. I know that I could just edit /etc/sudoers
:
Defaults timestamp_timeout=15
That ought to fix it...but I feel like there should be a better solution here that either I'm not seeing or haven't yet explored. If we could run it as a python child process with prexec_fn
, that would be ideal.