py.lib

Yohn Y. 2022-02-23 Parent:af2bf518950a

23:1668cc57225b Go to Latest

py.lib/ssh_tools.py

. Рефакторинг бессмысленный и беспощадный

History
     1.1 --- a/ssh_tools.py	Sat Nov 27 12:29:59 2021 +0300
     1.2 +++ b/ssh_tools.py	Wed Feb 23 19:27:33 2022 +0300
     1.3 @@ -11,387 +11,423 @@
     1.4  HOSTKEY_warn = 1
     1.5  HOSTKEY_reject = 2
     1.6  
     1.7 -def promptChecker(user, host, buf):
     1.8 -	Signs = ['[', ']', '#', '<', '>', '$', '!', '%', '(', ')', '@', '+', ':', ';', ' ', '\t']
     1.9 -	isPrompt = False
    1.10 -	isSep = True
    1.11 -	newLites = 0
    1.12 -	endBuf = ''
    1.13 -	for i in range(1, len(buf) + 1):
    1.14 -		if not isPrompt:
    1.15 -			if buf[-i] == '\n':
    1.16 -				endBuf = buf[-i] + endBuf
    1.17 -				continue
    1.18 -			isPrompt = True
    1.19 -		if isSep:
    1.20 -			if buf[-i] in Signs:
    1.21 -				endBuf = buf[-i] + endBuf
    1.22 -				continue
    1.23 -			isSep = False
    1.24 -		if buf[-i] == '\n':
    1.25 -			break
    1.26 -	_startProc = len(buf) - i
    1.27 -	_endProc = len(buf) - len(endBuf)
    1.28 -	buf = buf[_startProc:_endProc]
    1.29 -	searchCond = []
    1.30 -	for i in [user, host]:
    1.31 -		bufL = ''
    1.32 -		bufR = ''
    1.33 -		index = buf.find(i)
    1.34 -		if index != -1:
    1.35 -			for ch in buf[:index][::-1]:
    1.36 -				if ch in Signs:
    1.37 -					bufL = ch + bufL
    1.38 -				else:
    1.39 -					break
    1.40 -			index = index + len(i)
    1.41 -			for ch in buf[index:]:
    1.42 -				if ch in Signs:
    1.43 -					bufR += ch
    1.44 -				else:
    1.45 -					break
    1.46 -			searchCond.append(bufL + i + bufR)
    1.47 -	
    1.48 -	def Check(buf):
    1.49 -		if buf.endswith(endBuf):
    1.50 -			endSearch = len(buf) - len(endBuf)
    1.51 -			startSearch = buf.rfind('\n', 0, len(buf) - len(endBuf))
    1.52 -			
    1.53 -			if startSearch == -1: startSearch = 0
    1.54 -			
    1.55 -			_buf = buf[startSearch:endSearch]
    1.56 -			for i in searchCond:
    1.57 -				if _buf.find(i) == -1: return False
    1.58 -			return True
    1.59 -		else:
    1.60 -			return False
    1.61 -	return Check		
    1.62 -		
    1.63 +
    1.64 +def prompt_checker(user, host, buf):
    1.65 +    signs = ['[', ']', '#', '<', '>', '$', '!', '%', '(', ')', '@', '+', ':', ';', ' ', '\t']
    1.66 +    is_prompt = False
    1.67 +    is_sep = True
    1.68 +    end_buf = ''
    1.69 +
    1.70 +    ch_pos = 0
    1.71 +    for ch_pos in range(1, len(buf) + 1):
    1.72 +        if not is_prompt:
    1.73 +            if buf[-ch_pos] == '\n':
    1.74 +                end_buf = buf[-ch_pos] + end_buf
    1.75 +                continue
    1.76 +            is_prompt = True
    1.77 +
    1.78 +        if is_sep:
    1.79 +            if buf[-ch_pos] in signs:
    1.80 +                end_buf = buf[-ch_pos] + end_buf
    1.81 +                continue
    1.82 +            is_sep = False
    1.83 +
    1.84 +        if buf[-ch_pos] == '\n':
    1.85 +            break
    1.86 +
    1.87 +    _startProc = len(buf) - ch_pos
    1.88 +    _endProc = len(buf) - len(end_buf)
    1.89 +    buf = buf[_startProc:_endProc]
    1.90 +    search_cond = []
    1.91  
    1.92 -class SSHError(Exception): pass
    1.93 +    for ch_pos in [user, host]:
    1.94 +        buf_l = ''
    1.95 +        buf_r = ''
    1.96 +        index = buf.find(ch_pos)
    1.97 +        if index != -1:
    1.98 +            for ch in buf[:index][::-1]:
    1.99 +                if ch in signs:
   1.100 +                    buf_l = ch + buf_l
   1.101 +                else:
   1.102 +                    break
   1.103 +            index = index + len(ch_pos)
   1.104 +            for ch in buf[index:]:
   1.105 +                if ch in signs:
   1.106 +                    buf_r += ch
   1.107 +                else:
   1.108 +                    break
   1.109 +            search_cond.append(buf_l + ch_pos + buf_r)
   1.110 +
   1.111 +    def check(check_buf):
   1.112 +        if check_buf.endswith(end_buf):
   1.113 +            end_search = len(check_buf) - len(end_buf)
   1.114 +            start_search = check_buf.rfind('\n', 0, len(check_buf) - len(end_buf))
   1.115 +
   1.116 +            if start_search == -1:
   1.117 +                start_search = 0
   1.118 +
   1.119 +            _buf = check_buf[start_search:end_search]
   1.120 +            for i in search_cond:
   1.121 +                if _buf.find(i) == -1:
   1.122 +                    return False
   1.123 +
   1.124 +            return True
   1.125 +
   1.126 +        else:
   1.127 +            return False
   1.128 +
   1.129 +    return check
   1.130 +
   1.131 +
   1.132 +class SSHError(Exception):
   1.133 +    pass
   1.134 +
   1.135  
   1.136  class TOCheck(object):
   1.137 -	"""
   1.138 -	Взято из: https://bitbucket.org/awgur/pylib/src/default/timetools.py	
   1.139 -	"""
   1.140 -	def __init__(self, timeOut):
   1.141 -		self.start = datetime.now()
   1.142 -		self.timeOut = timeOut
   1.143 -		                           
   1.144 -	def __call__(self, timeOut=None):
   1.145 -		if not timeOut:
   1.146 -			timeOut = self.timeOut
   1.147 -			
   1.148 -			buf = datetime.now() - self.start
   1.149 -			
   1.150 -            if buf.seconds > timeOut:
   1.151 -				return True
   1.152 -			else:
   1.153 -				return False
   1.154 -				
   1.155 -	def __bool__(self):
   1.156 -		return not self():
   1.157 +    """
   1.158 +    Взято из: https://bitbucket.org/awgur/pylib/src/default/timetools.py
   1.159 +    """
   1.160 +    def __init__(self, timeout):
   1.161 +        self.start = datetime.now()
   1.162 +        self.timeout = timeout
   1.163 +
   1.164 +    def __call__(self, timeout=None):
   1.165 +        if not timeout:
   1.166 +            timeout = self.timeout
   1.167 +
   1.168 +            buf = datetime.now() - self.start
   1.169 +
   1.170 +            if buf.seconds > timeout:
   1.171 +                return True
   1.172 +
   1.173 +            else:
   1.174 +                return False
   1.175 +
   1.176 +    def __bool__(self):
   1.177 +        return not self()
   1.178  
   1.179  
   1.180  class SSHSubsh(object):
   1.181 -	"""Класс для облегчения работы с контекстами, когда приглашение коммандной оболочки 
   1.182 -	меняется в результате исполнения комманды.
   1.183 -	"""
   1.184 -	def __init__(self, ssh, prompt):
   1.185 -		self.ssh = ssh
   1.186 -		self.prompt = SSHPromptCheck(prompt)
   1.187 -		
   1.188 -	def __call__(self, cmd):
   1.189 -		res = self.ssh(cmd, wait=False)
   1.190 -		res += self.waitPrompt(self.prompt)
   1.191 -		return res
   1.192 +    """Класс для облегчения работы с контекстами, когда приглашение коммандной оболочки
   1.193 +    меняется в результате исполнения комманды.
   1.194 +    """
   1.195 +    def __init__(self, ssh, prompt):
   1.196 +        self.ssh = ssh
   1.197 +        self.prompt = SSHPromptCheck(prompt)
   1.198 +
   1.199 +    def __call__(self, cmd):
   1.200 +        res = self.ssh(cmd, wait=False)
   1.201 +        res += self.waitPrompt(self.prompt)
   1.202 +        return res
   1.203 +
   1.204  
   1.205  class SSHPromptCheck(object):
   1.206 -	"""
   1.207 -	Проверяет, появилось ли приглашение коммандной строки в выводе сервера
   1.208 -	
   1.209 -	Принимает:
   1.210 -	  - prompt:
   1.211 -	      Строка, которая должна однозначно идентифицировать приглашение 
   1.212 -	      коммандной строки, либо функция которой передаётся строка, и она 
   1.213 -	      должна вернуть True, если строка завершается приглашением коммандной
   1.214 -	      строки либо False в обратном случае. Кроме того можно передат сам объект,
   1.215 -	      созданный заранее.
   1.216 -	"""
   1.217 -	def __init__(self, prompt):
   1.218 -		if isinstance(prompt, self.__class__):
   1.219 -			self.prompt = prompt.prompt
   1.220 -			self.check = prompt.check
   1.221 -		else:
   1.222 -			def isFunc(): pass
   1.223 -			if type(prompt) == type(isFunc):
   1.224 -				self.check = prompt
   1.225 -				self.prompt = None
   1.226 -			else:
   1.227 -				self.prompt = prompt
   1.228 -			
   1.229 -			if self.prompt == None:
   1.230 -				raise SSHError('Prompt not set')
   1.231 -			
   1.232 -		
   1.233 -	def check(self, buf):
   1.234 -		if buf.endswith(self.prompt):
   1.235 -			return True
   1.236 -		else:
   1.237 -			return False
   1.238 -	
   1.239 -	def __call__(self, buf):
   1.240 -		if isinstance(buf, SSHOutput):
   1.241 -			return self.check(buf.out)
   1.242 -		elif buf:
   1.243 -			return self.check(buf)
   1.244 -		else:
   1.245 -			return False
   1.246 -			
   1.247 -		
   1.248 +    """
   1.249 +    Проверяет, появилось ли приглашение коммандной строки в выводе сервера
   1.250 +
   1.251 +    Принимает:
   1.252 +      - prompt:
   1.253 +          Строка, которая должна однозначно идентифицировать приглашение
   1.254 +          коммандной строки, либо функция которой передаётся строка, и она
   1.255 +          должна вернуть True, если строка завершается приглашением коммандной
   1.256 +          строки либо False в обратном случае. Кроме того можно передат сам объект,
   1.257 +          созданный заранее.
   1.258 +    """
   1.259 +    def __init__(self, prompt):
   1.260 +        if isinstance(prompt, self.__class__):
   1.261 +            self.prompt = prompt.prompt
   1.262 +            self.check = prompt.check
   1.263 +
   1.264 +        else:
   1.265 +            def is_func():
   1.266 +                pass
   1.267 +
   1.268 +            if type(prompt) == type(is_func):
   1.269 +                self.check = prompt
   1.270 +                self.prompt = None
   1.271 +
   1.272 +            else:
   1.273 +                self.prompt = prompt
   1.274 +
   1.275 +            if self.prompt is None:
   1.276 +                raise SSHError('Prompt not set')
   1.277 +
   1.278 +    def check(self, buf):
   1.279 +        if buf.endswith(self.prompt):
   1.280 +            return True
   1.281 +
   1.282 +        else:
   1.283 +            return False
   1.284 +
   1.285 +    def __call__(self, buf):
   1.286 +        if isinstance(buf, SSHOutput):
   1.287 +            return self.check(buf.out)
   1.288 +
   1.289 +        elif buf:
   1.290 +            return self.check(buf)
   1.291 +
   1.292 +        else:
   1.293 +            return False
   1.294 +
   1.295 +
   1.296  class SSHOutput(object):
   1.297 -	"""Содержит вывод удалённого сервера и помогает управляться с ним.
   1.298 -	"""
   1.299 -	def __init__(self, out = '', err = ''):
   1.300 -		self.out = out
   1.301 -		self.err = err
   1.302 -		
   1.303 -	
   1.304 -	def error(self, buf):
   1.305 -		"Добавить буфер к буферу сообщения об ошибке"
   1.306 -		self.err += buf
   1.307 -		
   1.308 -	def __add__(self, buf):
   1.309 -		if isinstance(buf, self.__class__):
   1.310 -			self.out += buf.out
   1.311 -			self.err += buf.err
   1.312 -		else:	
   1.313 -			self.out += buf
   1.314 -		return self
   1.315 -		
   1.316 -	def __str__(self):
   1.317 -		return self.out
   1.318 -	
   1.319 -	def getError(self):
   1.320 -		return self.err
   1.321 -	
   1.322 -	def __bool__(self):
   1.323 -		if self.out or self.err:
   1.324 -			return True
   1.325 -		else:
   1.326 -			return False
   1.327 -	
   1.328 -	def __repr__(self):
   1.329 -		buf = ''
   1.330 -		buf += '---- OUTPUT -----------'
   1.331 -		buf += self.out
   1.332 -		buf += '---- ERRORS -----------'
   1.333 -		buf += self.err
   1.334 -		return buf
   1.335 -		
   1.336 -	def __getitem__(self, key):
   1.337 -		return self.out.splittines()[key]
   1.338 -		
   1.339 -	def __iter__(self):
   1.340 -		for line in self.out.splitlines():
   1.341 -			yield line
   1.342 -	
   1.343 -	def isEol(self):
   1.344 -		if self.out[-1] == '\n':
   1.345 -			return True
   1.346 -		else:
   1.347 -			return False
   1.348 -			
   1.349 -			
   1.350 +    """Содержит вывод удалённого сервера и помогает управляться с ним.
   1.351 +    """
   1.352 +
   1.353 +    def __init__(self, out='', err=''):
   1.354 +        self.out = out
   1.355 +        self.err = err
   1.356 +
   1.357 +    def error(self, buf):
   1.358 +        """Добавить буфер к буферу сообщения об ошибке"""
   1.359 +
   1.360 +        self.err += buf
   1.361 +
   1.362 +    def __add__(self, buf):
   1.363 +        if isinstance(buf, self.__class__):
   1.364 +            self.out += buf.out
   1.365 +            self.err += buf.err
   1.366 +        else:
   1.367 +            self.out += buf
   1.368 +        return self
   1.369 +
   1.370 +    def __str__(self):
   1.371 +        return self.out
   1.372 +
   1.373 +    def get_error(self):
   1.374 +        return self.err
   1.375 +
   1.376 +    def __bool__(self):
   1.377 +        if self.out or self.err:
   1.378 +            return True
   1.379 +        else:
   1.380 +            return False
   1.381 +
   1.382 +    def __repr__(self):
   1.383 +        buf = ''
   1.384 +        buf += '---- OUTPUT -----------'
   1.385 +        buf += self.out
   1.386 +        buf += '---- ERRORS -----------'
   1.387 +        buf += self.err
   1.388 +        return buf
   1.389 +
   1.390 +    def __getitem__(self, key):
   1.391 +        return self.out.splittines()[key]
   1.392 +
   1.393 +    def __iter__(self):
   1.394 +        for line in self.out.splitlines():
   1.395 +            yield line
   1.396 +
   1.397 +    def is_eol(self):
   1.398 +        if self.out[-1] == '\n':
   1.399 +            return True
   1.400 +        else:
   1.401 +            return False
   1.402 +
   1.403 +
   1.404  class SSHCommunicate(object):
   1.405 -	"""Взаимодействие с командой ssh. В сосотоянии отправлять ей данные и принимать данные от неё.
   1.406 -	
   1.407 -	Обеспчивает работу с exec_command в SSH
   1.408 -	"""
   1.409 -	def __init__(self, stdin, stdout, stderr):
   1.410 -		self.inC = stdin
   1.411 -		self.out = stdout
   1.412 -		self.err = stderr
   1.413 -		
   1.414 -	def __call__(self, buf=None):
   1.415 -		if buf != None:
   1.416 -			self.inC.write(buf)
   1.417 -		return SSHOutput(self.out.read(), self.err.read())
   1.418 -	
   1.419 -	def __str__(self):
   1.420 -		return str(self())
   1.421 -		
   1.422 -	def __repr__(self):
   1.423 -		return repr(self())
   1.424 +    """\
   1.425 +    Взаимодействие с командой ssh. В сосотоянии отправлять ей данные и принимать данные от неё.
   1.426 +
   1.427 +    Обеспечивает работу с exec_command в SSH
   1.428 +    """
   1.429 +
   1.430 +    def __init__(self, stdin, stdout, stderr):
   1.431 +        self.inC = stdin
   1.432 +        self.out = stdout
   1.433 +        self.err = stderr
   1.434 +
   1.435 +    def __call__(self, buf=None):
   1.436 +        if buf is not None:
   1.437 +            self.inC.write(buf)
   1.438 +        return SSHOutput(self.out.read(), self.err.read())
   1.439 +
   1.440 +    def __str__(self):
   1.441 +        return str(self())
   1.442 +
   1.443 +    def __repr__(self):
   1.444 +        return repr(self())
   1.445 +
   1.446  
   1.447  class _SSH(object):
   1.448 -	"""Метакласс для SSH соединений
   1.449 -	
   1.450 -	Принимает:
   1.451 -	  - host: Имя узла
   1.452 -	  - user: Имя пользователя
   1.453 -	  - passwd(не обязательно, если есть key): пароль пользователя
   1.454 -	  - key(не обязательно если есть passwd): файл ключа
   1.455 -	  - hostKeyPol[HOSTKEY_autoAdd | HOSTKEY_warn | HOSTKEY_reject]:
   1.456 -	      HOSTKEY_autoAdd(По умолчанию): 
   1.457 -	        если ключ удалённого узла нам неизвестен, добавить, соединение разрешить.
   1.458 -	      HOSTKEY_warn: если ключ удалённого узла нам неизвестен, предупредить.
   1.459 -	      HOSTKEY_reject: если ключ удалённого узла нам неизвестен, разорвать соединение.
   1.460 -	  - timeout: таймаут операций с сервером.
   1.461 -	"""
   1.462 -	def __init__(self, host, user, passwd=None, key=None, 
   1.463 -			hostKeyPol=HOSTKEY_autoAdd, timeout=None
   1.464 -		):
   1.465 -		if passwd == None and key == None:
   1.466 -			raise SSHError('Auth type not set')
   1.467 -				
   1.468 -		if hostKeyPol == HOSTKEY_autoAdd:
   1.469 -			_hostKeyPol = paramiko.AutoAddPolicy()
   1.470 -		elif hostKeyPol == HOSTKEY_warn:
   1.471 -			_hostKeyPol = paramiko.WarningPolicy()
   1.472 -		elif hostKeyPol == HOSTKEY_reject:
   1.473 -			_hostKeyPol = paramiko.RejectPolicy()
   1.474 -		else:
   1.475 -			raise SSHError('Unknown policy type')
   1.476 -		
   1.477 -		self.ssh = paramiko.SSHClient()	
   1.478 -		self.ssh.set_missing_host_key_policy(_hostKeyPol)	
   1.479 -		if passwd:
   1.480 -			self.ssh.connect(hostname=host, username=user, password=passwd, look_for_keys=False, allow_agent=False)
   1.481 -		else:
   1.482 -			self.ssh.connect(hostname=host, username=user, key_filename=key, look_for_keys=False, allow_agent=False)
   1.483 -			
   1.484 -		if timeout != None:
   1.485 -			self.timeout = timeout
   1.486 -		else:
   1.487 -			self.timeout = TIMEOUT
   1.488 -		
   1.489 -		self.user = user
   1.490 -		self.host = host
   1.491 -	
   1.492 -	def __del__(self):
   1.493 -		try:
   1.494 -			self.ssh.close()
   1.495 -		except:
   1.496 -			pass
   1.497 -		del self.ssh		
   1.498 -		
   1.499 +    """\
   1.500 +    Метакласс для SSH соединений
   1.501 +
   1.502 +    Принимает:
   1.503 +      - host: Имя узла
   1.504 +      - user: Имя пользователя
   1.505 +      - passwd(не обязательно, если есть key): пароль пользователя
   1.506 +      - key(не обязательно если есть passwd): файл ключа
   1.507 +      - hostKeyPol[HOSTKEY_autoAdd | HOSTKEY_warn | HOSTKEY_reject]:
   1.508 +          HOSTKEY_autoAdd(По умолчанию):
   1.509 +            если ключ удалённого узла нам неизвестен, добавить, соединение разрешить.
   1.510 +          HOSTKEY_warn: если ключ удалённого узла нам неизвестен, предупредить.
   1.511 +          HOSTKEY_reject: если ключ удалённого узла нам неизвестен, разорвать соединение.
   1.512 +      - timeout: таймаут операций с сервером.
   1.513 +    """
   1.514 +
   1.515 +    def __init__(self, host, user, passwd=None, key=None,
   1.516 +                 host_key_pol=HOSTKEY_autoAdd, timeout=None
   1.517 +                 ):
   1.518 +
   1.519 +        if passwd is None and key is None:
   1.520 +            raise SSHError('Auth type not set')
   1.521 +
   1.522 +        if host_key_pol == HOSTKEY_autoAdd:
   1.523 +            _hostKeyPol = paramiko.AutoAddPolicy()
   1.524 +        elif host_key_pol == HOSTKEY_warn:
   1.525 +            _hostKeyPol = paramiko.WarningPolicy()
   1.526 +        elif host_key_pol == HOSTKEY_reject:
   1.527 +            _hostKeyPol = paramiko.RejectPolicy()
   1.528 +        else:
   1.529 +            raise SSHError('Unknown policy type')
   1.530 +
   1.531 +        self.ssh = paramiko.SSHClient()
   1.532 +        self.ssh.set_missing_host_key_policy(_hostKeyPol)
   1.533 +        if passwd:
   1.534 +            self.ssh.connect(hostname=host, username=user, password=passwd, look_for_keys=False, allow_agent=False)
   1.535 +        else:
   1.536 +            self.ssh.connect(hostname=host, username=user, key_filename=key, look_for_keys=False, allow_agent=False)
   1.537 +
   1.538 +        if timeout is not None:
   1.539 +            self.timeout = timeout
   1.540 +
   1.541 +        else:
   1.542 +            self.timeout = TIMEOUT
   1.543 +
   1.544 +        self.user = user
   1.545 +        self.host = host
   1.546 +
   1.547 +    def __del__(self):
   1.548 +        try:
   1.549 +            self.ssh.close()
   1.550 +
   1.551 +        except:
   1.552 +            pass
   1.553 +
   1.554 +        del self.ssh
   1.555 +
   1.556 +
   1.557  class InterSSH(_SSH):
   1.558 -	"""Класс Взаимодействия с сервером SSH
   1.559 -	
   1.560 -	Кроме аргументов необходимых для метакласса принимает:
   1.561 -	  - prompt: 
   1.562 -	      Параметр конструктора SSHPromptCheck. Принимается строго по имени.
   1.563 -	"""
   1.564 -	def __init__(self, *a, **kwa):
   1.565 -		if 'prompt' in kwa:
   1.566 -			prompt = kwa['prompt']
   1.567 -			del kwa['prompt']
   1.568 -			
   1.569 -		_SSH.__init__(self, *a, **kwa)
   1.570 -		
   1.571 -		self.shell = self.ssh.invoke_shell()
   1.572 -		self.shell.settimeout(self.timeout)
   1.573 -		if prompt == None:
   1.574 -			prompt = self._getPrompt()
   1.575 -			self.ready = True
   1.576 -		else:
   1.577 -			self.ready = False
   1.578 -		self.prompt = SSHPromptCheck(prompt)
   1.579 +    """Класс Взаимодействия с сервером SSH
   1.580 +
   1.581 +    Кроме аргументов необходимых для метакласса принимает:
   1.582 +      - prompt:
   1.583 +          Параметр конструктора SSHPromptCheck. Принимается строго по имени.
   1.584 +    """
   1.585 +    def __init__(self, *a, **kwa):
   1.586 +        prompt = None
   1.587 +        if 'prompt' in kwa:
   1.588 +            prompt = kwa['prompt']
   1.589 +            del kwa['prompt']
   1.590 +
   1.591 +        _SSH.__init__(self, *a, **kwa)
   1.592 +
   1.593 +        self.shell = self.ssh.invoke_shell()
   1.594 +        self.shell.settimeout(self.timeout)
   1.595 +        if prompt is None:
   1.596 +            prompt = self._get_prompt()
   1.597 +            self.ready = True
   1.598 +
   1.599 +        else:
   1.600 +            self.ready = False
   1.601 +
   1.602 +        self.prompt = SSHPromptCheck(prompt)
   1.603  
   1.604 -		
   1.605 -	def __bool__(self):
   1.606 -		"Готово ли соединение принимать новые комманды"
   1.607 -		return self.ready
   1.608 -	
   1.609 -	def _getPrompt(self):
   1.610 -		"""Возвращает объект проверки на приглашение комммандной строки из текщего
   1.611 -		буфера вывода.
   1.612 -		"""
   1.613 -		buf = ''
   1.614 -		while self.shell.recv_ready():
   1.615 -			buf += self.shell.recv(1024)
   1.616 -		
   1.617 -		func = promptChecker(self.user, self.host, buf)
   1.618 -		return SSHPromptCheck(func)
   1.619 +    def __bool__(self):
   1.620 +        """Готово ли соединение принимать новые команды"""
   1.621 +        return self.ready
   1.622 +
   1.623 +    def _get_prompt(self):
   1.624 +        """Возвращает объект проверки на приглашение комммандной строки из текщего
   1.625 +        буфера вывода.
   1.626 +        """
   1.627 +        buf = ''
   1.628 +        while self.shell.recv_ready():
   1.629 +            buf += self.shell.recv(1024)
   1.630 +
   1.631 +        func = prompt_checker(self.user, self.host, buf)
   1.632 +        return SSHPromptCheck(func)
   1.633 +
   1.634 +    def wait_prompt(self, prompt=None):
   1.635 +        """\
   1.636 +        Ожидание приглашения командной строки
   1.637  
   1.638 -	
   1.639 -	def waitPrompt(self, prompt=None):
   1.640 -		"""Ожидание приглашения коммандной строки
   1.641 -		
   1.642 -		Принимает необязательный аргумент: Экземпляр класса SSHPromptCheck, с помощью котороого 
   1.643 -		проверяется присутствие приглашения командного интерпретатора в выводе.
   1.644 -		"""
   1.645 -		if prompt == None:
   1.646 -			prompt = self.prompt
   1.647 -		else:
   1.648 -			prompt = SSHPromptCheck(prompt)
   1.649 -			
   1.650 -		if not self.ready:
   1.651 -			timeCheck = TOCheck(self.timeout)
   1.652 -			res = SSHOutput()
   1.653 -			while True:
   1.654 -				while self.shell.recv_stderr_ready():
   1.655 -					res.error(self.shell.recv_stderr(1024))
   1.656 +        Принимает необязательный аргумент: Экземпляр класса SSHPromptCheck, с помощью котороого
   1.657 +        проверяется присутствие приглашения командного интерпретатора в выводе.
   1.658 +        """
   1.659 +
   1.660 +        if prompt is None:
   1.661 +            prompt = self.prompt
   1.662 +
   1.663 +        else:
   1.664 +            prompt = SSHPromptCheck(prompt)
   1.665  
   1.666 -				while self.shell.recv_ready():
   1.667 -					res += self.shell.recv(1024)
   1.668 +        res = SSHOutput()
   1.669 +        if not self.ready:
   1.670 +            time_check = TOCheck(self.timeout)
   1.671 +            while True:
   1.672 +                while self.shell.recv_stderr_ready():
   1.673 +                    res.error(self.shell.recv_stderr(1024))
   1.674 +
   1.675 +                while self.shell.recv_ready():
   1.676 +                    res += self.shell.recv(1024)
   1.677 +
   1.678 +                if prompt(res):
   1.679 +                    break
   1.680  
   1.681 -				if prompt(res):
   1.682 -					break
   1.683 -		
   1.684 -				if timeCheck():
   1.685 -					raise SSHError('Command call timeout\n' + repr(res))
   1.686 -		
   1.687 -		self.ready = True
   1.688 -		return res
   1.689 +                if time_check():
   1.690 +                    raise SSHError('Command call timeout\n' + repr(res))
   1.691 +
   1.692 +        self.ready = True
   1.693 +        return res
   1.694 +
   1.695 +    def __call__(self, cmd, wait=True):
   1.696 +        """Запуск команды
   1.697 +
   1.698 +        Принимает:
   1.699 +          - cmd: Комманда
   1.700 +          - wait(необязательный аргумент): Признак ожидания завершения комманды.
   1.701  
   1.702 -	def __call__(self, cmd, wait=True):
   1.703 -		"""Запуск команды
   1.704 -		
   1.705 -		Принимает:
   1.706 -		  - cmd: Комманда
   1.707 -		  - wait(необязательный аргумент): Признак ожидания завершения комманды.
   1.708 -		  
   1.709 -		Возвращает: Экземпляр класса SSHOutput
   1.710 -		"""
   1.711 -		res = SSHOutput()
   1.712 -		if not self.ready:
   1.713 -			res += self.waitPrompt()
   1.714 -		bytes = self.shell.send('%s\n' % cmd)
   1.715 -		if bytes == 0:
   1.716 -			raise SSHError('Channel closed')
   1.717 -		if wait:
   1.718 -			res += self.waitPrompt()
   1.719 -		else:
   1.720 -			self.ready = False
   1.721 -		return res
   1.722 +        Возвращает: Экземпляр класса SSHOutput
   1.723 +        """
   1.724 +        res = SSHOutput()
   1.725 +        if not self.ready:
   1.726 +            res += self.wait_prompt()
   1.727 +        bytes = self.shell.send('%s\n' % cmd)
   1.728 +        if bytes == 0:
   1.729 +            raise SSHError('Channel closed')
   1.730 +        if wait:
   1.731 +            res += self.wait_prompt()
   1.732 +        else:
   1.733 +            self.ready = False
   1.734 +        return res
   1.735  
   1.736 -	def subShell(self, cmd, prompt=None):
   1.737 -		"""Возвращает объект SSHSubsh, через который удобно работать 
   1.738 -		интерпретаторами, запускаемыми из текущего, либо с ситуацией изменения приглашения 
   1.739 -		командного интерпретатора. 
   1.740 -		"""
   1.741 -		self(cmd, wait=False)
   1.742 -		if prompt == None:
   1.743 -			prompt = self._getPropt()
   1.744 -		return SSHSubsh(self, prompt)
   1.745 -			
   1.746 -	def close(self):
   1.747 -		res = SSHOutput
   1.748 -		if not self:
   1.749 -			res += self.waitPrompt()
   1.750 -		self.ssh.close()
   1.751 -		return res
   1.752 +    def sub_shell(self, cmd, prompt=None):
   1.753 +        """Возвращает объект SSHSubsh, через который удобно работать
   1.754 +        интерпретаторами, запускаемыми из текущего, либо с ситуацией изменения приглашения
   1.755 +        командного интерпретатора.
   1.756 +        """
   1.757 +        self(cmd, wait=False)
   1.758 +        if prompt is None:
   1.759 +            prompt = self._getPropt()
   1.760 +        return SSHSubsh(self, prompt)
   1.761 +
   1.762 +    def close(self):
   1.763 +        res = SSHOutput
   1.764 +        if not self:
   1.765 +            res += self.wait_prompt()
   1.766 +        self.ssh.close()
   1.767 +        return res
   1.768 +
   1.769  
   1.770  class SSH(_SSH):
   1.771 -	"""Класс призванный управлять выполнением единичных комманд, без привлечения контекста.
   1.772 -	
   1.773 -	Принимает аргументы необходимые для метакласса _SSH
   1.774 -	"""
   1.775 -	def __init__(self, *a, **kwa):
   1.776 -		_SSH.__init__(self, *a, **kwa)
   1.777 -		
   1.778 -	def __call__(self, cmd):
   1.779 -		return SSHCommunicate(*self.ssh.exec_command(cmd, timeout=self.timeout))
   1.780 -		
   1.781 \ No newline at end of file
   1.782 +    """Класс призванный управлять выполнением единичных комманд, без привлечения контекста.
   1.783 +
   1.784 +    Принимает аргументы необходимые для метакласса _SSH
   1.785 +    """
   1.786 +    def __init__(self, *a, **kwa):
   1.787 +        _SSH.__init__(self, *a, **kwa)
   1.788 +
   1.789 +    def __call__(self, cmd):
   1.790 +        return SSHCommunicate(*self.ssh.exec_command(cmd, timeout=self.timeout))