interpret stderr and raise custom exceptions
1. Detects failed authentication message from Windows systems and raises SatoriSMBAuthenticationException 2. Detects error message stating that the user has been locked out of a Windows system and raises SatoriSMBLockoutException 3. Detects error message stating shared access flags are incompatible on a Windows system and raises SatoriSMBFileSharingException Consolidates (DRY) the logic which listens to command output in smb.py so that the custom Exceptions mentioned above can be raised if any of the known error output is encountered. Unchanged: A non-zero exit status with an unknown error message raises a SubprocessError including that error message. Previously, all error messages corresponding to non-zero exit codes were "unknown". Closes-Bug: #1389034 Change-Id: I157adfe9034177f7975473ff96f29fc17c6ad12b
This commit is contained in:
parent
5f7272abf7
commit
dea382bae1
|
@ -46,6 +46,26 @@ class SatoriShellException(SatoriException):
|
|||
"""Invalid shell parameters."""
|
||||
|
||||
|
||||
class SatoriAuthenticationException(SatoriException):
|
||||
|
||||
"""Invalid login credentials."""
|
||||
|
||||
|
||||
class SatoriSMBAuthenticationException(SatoriAuthenticationException):
|
||||
|
||||
"""Invalid login credentials for use over SMB to server."""
|
||||
|
||||
|
||||
class SatoriSMBLockoutException(SatoriSMBAuthenticationException):
|
||||
|
||||
"""Too many invalid logon attempts, the user has been locked out."""
|
||||
|
||||
|
||||
class SatoriSMBFileSharingException(SatoriException):
|
||||
|
||||
"""Incompatible shared access flags for a file on the Windows system."""
|
||||
|
||||
|
||||
class GetPTYRetryFailure(SatoriException):
|
||||
|
||||
"""Tried to re-run command with get_pty to no avail."""
|
||||
|
|
|
@ -29,6 +29,7 @@ import shlex
|
|||
import subprocess
|
||||
import tempfile
|
||||
|
||||
from satori import errors
|
||||
from satori import ssh
|
||||
from satori import tunnel
|
||||
|
||||
|
@ -277,6 +278,33 @@ class SMBClient(object): # pylint: disable=R0902
|
|||
return self.remote_execute(command, powershell=powershell,
|
||||
retry=retry - 1)
|
||||
|
||||
def _handle_output(self, output):
|
||||
"""Check for process termination, exit code, or error messages.
|
||||
|
||||
If the exit code is available and is zero, return True. This rountine
|
||||
will raise an exception in the case of a non-zero exit code.
|
||||
"""
|
||||
if self._process.poll() is not None:
|
||||
if self._process.returncode == 0:
|
||||
return True
|
||||
if "The attempted logon is invalid" in output:
|
||||
msg = [k for k in output.splitlines() if k][-1].strip()
|
||||
raise errors.SatoriSMBAuthenticationException(msg)
|
||||
elif "The user account has been automatically locked" in output:
|
||||
msg = [k for k in output.splitlines() if k][-1].strip()
|
||||
raise errors.SatoriSMBLockoutException(msg)
|
||||
elif "cannot be opened because the share access flags" in output:
|
||||
# A file cannot be opened because the share
|
||||
# access flags are incompatible
|
||||
msg = [k for k in output.splitlines() if k][-1].strip()
|
||||
raise errors.SatoriSMBFileSharingException(msg)
|
||||
else:
|
||||
raise SubprocessError("subprocess with pid: %s has "
|
||||
"terminated unexpectedly with "
|
||||
"return code: %s | %s"
|
||||
% (self._process.pid,
|
||||
self._process.poll(), output))
|
||||
|
||||
def _get_output(self, prompt_expected=True, wait=500):
|
||||
"""Retrieve output from _process.
|
||||
|
||||
|
@ -293,15 +321,8 @@ class SMBClient(object): # pylint: disable=R0902
|
|||
tmp_out += self._file_read.read()
|
||||
# leave loop if underlying process has a return code
|
||||
# obviously meaning that it has terminated
|
||||
if self._process.poll() is not None:
|
||||
if self._process.returncode == 0:
|
||||
break
|
||||
error = tmp_out
|
||||
raise SubprocessError("subprocess with pid: %s has terminated "
|
||||
"unexpectedly with return code: %s | %s"
|
||||
% (self._process.pid,
|
||||
self._process.poll(), error))
|
||||
time.sleep(0)
|
||||
if self._handle_output(tmp_out):
|
||||
break
|
||||
time.sleep(float(wait) / 1000)
|
||||
else:
|
||||
LOG.debug("Loop 1 - stdout read: %s", tmp_out)
|
||||
|
@ -315,15 +336,8 @@ class SMBClient(object): # pylint: disable=R0902
|
|||
stdout += tmp_out
|
||||
# leave loop if underlying process has a return code
|
||||
# obviously meaning that it has terminated
|
||||
if self._process.poll() is not None:
|
||||
if self._process.returncode == 0:
|
||||
break
|
||||
error = tmp_out
|
||||
raise SubprocessError("subprocess with pid: %s has terminated "
|
||||
"unexpectedly with return code: %s | %s"
|
||||
% (self._process.pid,
|
||||
self._process.poll(), error))
|
||||
time.sleep(0)
|
||||
if self._handle_output(tmp_out):
|
||||
break
|
||||
time.sleep(float(wait) / 1000)
|
||||
else:
|
||||
LOG.debug("Loop 2 - stdout read: %s", tmp_out)
|
||||
|
|
Loading…
Reference in New Issue