Commit c17fbf2f by Brian Coca

simplify become testing and handling, we had drifted and were doulbe checking…

simplify become testing and handling, we had drifted and were doulbe checking prompt, become and become_pass
fixed tests to conform to new signature and now tests both with and w/o password
now we are more explicit about self.prompt
parent eb0e7e19
...@@ -335,6 +335,7 @@ class PlayContext(Base): ...@@ -335,6 +335,7 @@ class PlayContext(Base):
prompt = None prompt = None
success_key = None success_key = None
self.prompt = None
if executable is None: if executable is None:
executable = C.DEFAULT_EXECUTABLE executable = C.DEFAULT_EXECUTABLE
...@@ -366,13 +367,14 @@ class PlayContext(Base): ...@@ -366,13 +367,14 @@ class PlayContext(Base):
# directly doesn't work, so we shellquote it with pipes.quote() and pass the quoted # directly doesn't work, so we shellquote it with pipes.quote() and pass the quoted
# string to the user's shell. We loop reading output until we see the randomly-generated # string to the user's shell. We loop reading output until we see the randomly-generated
# sudo prompt set with the -p option. # sudo prompt set with the -p option.
prompt = '[sudo via ansible, key=%s] password: ' % randbits
# force quick error if password is required but not supplied, should prevent sudo hangs. # force quick error if password is required but not supplied, should prevent sudo hangs.
if not self.become_pass: if self.become_pass:
flags += " -n " prompt = '[sudo via ansible, key=%s] password: ' % randbits
becomecmd = '%s %s -p "%s" -S -u %s %s -c %s' % (exe, flags, prompt, self.become_user, executable, success_cmd)
else:
becomecmd = '%s %s -n -S -u %s %s -c %s' % (exe, flags, self.become_user, executable, success_cmd)
becomecmd = '%s %s -S -p "%s" -u %s %s -c %s' % (exe, flags, prompt, self.become_user, executable, success_cmd)
elif self.become_method == 'su': elif self.become_method == 'su':
...@@ -415,7 +417,8 @@ class PlayContext(Base): ...@@ -415,7 +417,8 @@ class PlayContext(Base):
else: else:
raise AnsibleError("Privilege escalation method not found: %s" % self.become_method) raise AnsibleError("Privilege escalation method not found: %s" % self.become_method)
self.prompt = prompt if self.become_pass:
self.prompt = prompt
self.success_key = success_key self.success_key = success_key
return ('%s -c %s' % (executable, pipes.quote(becomecmd))) return ('%s -c %s' % (executable, pipes.quote(becomecmd)))
......
...@@ -70,7 +70,7 @@ class Connection(ConnectionBase): ...@@ -70,7 +70,7 @@ class Connection(ConnectionBase):
) )
self._display.debug("done running command with Popen()") self._display.debug("done running command with Popen()")
if self._play_context.prompt and self._play_context.become_pass and sudoable: if self._play_context.prompt and sudoable:
fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK) fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK)
fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK) fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK)
become_output = '' become_output = ''
......
...@@ -224,33 +224,32 @@ class Connection(ConnectionBase): ...@@ -224,33 +224,32 @@ class Connection(ConnectionBase):
try: try:
chan.exec_command(cmd) chan.exec_command(cmd)
if self._play_context.prompt: if self._play_context.prompt:
if self._play_context.become and self._play_context.become_pass: passprompt = False
passprompt = False while True:
while True: self._display.debug('Waiting for Privilege Escalation input')
self._display.debug('Waiting for Privilege Escalation input') if self.check_become_success(become_output):
if self.check_become_success(become_output): break
break elif self.check_password_prompt(become_output):
elif self.check_password_prompt(become_output): passprompt = True
passprompt = True break
break
chunk = chan.recv(bufsize)
chunk = chan.recv(bufsize) self._display.debug("chunk is: %s" % chunk)
self._display.debug("chunk is: %s" % chunk) if not chunk:
if not chunk: if 'unknown user' in become_output:
if 'unknown user' in become_output: raise AnsibleError( 'user %s does not exist' % become_user)
raise AnsibleError( 'user %s does not exist' % become_user)
else:
break
#raise AnsibleError('ssh connection closed waiting for password prompt')
become_output += chunk
if passprompt:
if self._play_context.become and self._play_context.become_pass:
chan.sendall(self._play_context.become_pass + '\n')
else: else:
raise AnsibleError("A password is reqired but none was supplied") break
#raise AnsibleError('ssh connection closed waiting for password prompt')
become_output += chunk
if passprompt:
if self._play_context.become and self._play_context.become_pass:
chan.sendall(self._play_context.become_pass + '\n')
else: else:
no_prompt_out += become_output raise AnsibleError("A password is reqired but none was supplied")
no_prompt_err += become_output else:
no_prompt_out += become_output
no_prompt_err += become_output
except socket.timeout: except socket.timeout:
raise AnsibleError('ssh timed out waiting for privilege escalation.\n' + become_output) raise AnsibleError('ssh timed out waiting for privilege escalation.\n' + become_output)
......
...@@ -378,54 +378,53 @@ class Connection(ConnectionBase): ...@@ -378,54 +378,53 @@ class Connection(ConnectionBase):
self._display.debug("Handling privilege escalation password prompt.") self._display.debug("Handling privilege escalation password prompt.")
if self._play_context.become and self._play_context.become_pass:
fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK)
fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK) fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK)
fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK)
become_output = ''
become_output = '' become_errput = ''
become_errput = '' passprompt = False
passprompt = False while True:
while True: self._display.debug('Waiting for Privilege Escalation input')
self._display.debug('Waiting for Privilege Escalation input')
if self.check_become_success(become_output + become_errput):
if self.check_become_success(become_output + become_errput): self._display.debug('Succeded!')
self._display.debug('Succeded!') break
break elif self.check_password_prompt(become_output) or self.check_password_prompt(become_errput):
elif self.check_password_prompt(become_output) or self.check_password_prompt(become_errput): self._display.debug('Password prompt!')
self._display.debug('Password prompt!') passprompt = True
passprompt = True break
break
self._display.debug('Read next chunks')
self._display.debug('Read next chunks') rfd, wfd, efd = select.select([p.stdout, p.stderr], [], [p.stdout], self._play_context.timeout)
rfd, wfd, efd = select.select([p.stdout, p.stderr], [], [p.stdout], self._play_context.timeout) if not rfd:
if not rfd: # timeout. wrap up process communication
# timeout. wrap up process communication stdout, stderr = p.communicate()
stdout, stderr = p.communicate() raise AnsibleError('Connection error waiting for privilege escalation password prompt: %s' % become_output)
raise AnsibleError('Connection error waiting for privilege escalation password prompt: %s' % become_output)
elif p.stderr in rfd:
elif p.stderr in rfd: chunk = p.stderr.read()
chunk = p.stderr.read() become_errput += chunk
become_errput += chunk self._display.debug('stderr chunk is: %s' % chunk)
self._display.debug('stderr chunk is: %s' % chunk) self.check_incorrect_password(become_errput)
self.check_incorrect_password(become_errput)
elif p.stdout in rfd:
elif p.stdout in rfd: chunk = p.stdout.read()
chunk = p.stdout.read() become_output += chunk
become_output += chunk self._display.debug('stdout chunk is: %s' % chunk)
self._display.debug('stdout chunk is: %s' % chunk)
if not chunk:
if not chunk: break
break #raise AnsibleError('Connection closed waiting for privilege escalation password prompt: %s ' % become_output)
#raise AnsibleError('Connection closed waiting for privilege escalation password prompt: %s ' % become_output)
if passprompt:
if passprompt: self._display.debug("Sending privilege escalation password.")
self._display.debug("Sending privilege escalation password.") stdin.write(self._play_context.become_pass + '\n')
stdin.write(self._play_context.become_pass + '\n') else:
else: no_prompt_out = become_output
no_prompt_out = become_output no_prompt_err = become_errput
no_prompt_err = become_errput
(returncode, stdout, stderr) = self._communicate(p, stdin, in_data, sudoable=sudoable) (returncode, stdout, stderr) = self._communicate(p, stdin, in_data, sudoable=sudoable)
......
...@@ -116,7 +116,7 @@ class TestPlayContext(unittest.TestCase): ...@@ -116,7 +116,7 @@ class TestPlayContext(unittest.TestCase):
default_cmd = "/bin/foo" default_cmd = "/bin/foo"
default_exe = "/bin/bash" default_exe = "/bin/bash"
sudo_exe = C.DEFAULT_SUDO_EXE or 'sudo' sudo_exe = C.DEFAULT_SUDO_EXE or 'sudo'
sudo_flags = C.DEFAULT_SUDO_FLAGS + " -n " sudo_flags = C.DEFAULT_SUDO_FLAGS
su_exe = C.DEFAULT_SU_EXE or 'su' su_exe = C.DEFAULT_SU_EXE or 'su'
su_flags = C.DEFAULT_SU_FLAGS or '' su_flags = C.DEFAULT_SU_FLAGS or ''
pbrun_exe = 'pbrun' pbrun_exe = 'pbrun'
...@@ -134,7 +134,12 @@ class TestPlayContext(unittest.TestCase): ...@@ -134,7 +134,12 @@ class TestPlayContext(unittest.TestCase):
play_context.become_method = 'sudo' play_context.become_method = 'sudo'
cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash") cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
self.assertEqual(cmd, """%s -c '%s %s -S -p "%s" -u %s %s -c '"'"'echo %s; %s'"'"''""" % (default_exe, sudo_exe, sudo_flags, play_context.prompt, play_context.become_user, default_exe, play_context.success_key, default_cmd)) self.assertEqual(cmd, """%s -c '%s %s -n -S -u %s %s -c '"'"'echo %s; %s'"'"''""" % (default_exe, sudo_exe, sudo_flags, play_context.become_user, default_exe, play_context.success_key, default_cmd))
play_context.become_pass = 'testpass'
cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
self.assertEqual(cmd, """%s -c '%s %s -p "%s" -S -u %s %s -c '"'"'echo %s; %s'"'"''""" % (default_exe, sudo_exe, sudo_flags, play_context.prompt, play_context.become_user, default_exe, play_context.success_key, default_cmd))
play_context.become_pass = None
play_context.become_method = 'su' play_context.become_method = 'su'
cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash") cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment