mirror of https://github.com/jumpserver/jumpserver
				
				
				
			perf: Custom secret change
							parent
							
								
									a9433bc48e
								
							
						
					
					
						commit
						c7eb170942
					
				| 
						 | 
				
			
			@ -97,7 +97,7 @@ def main():
 | 
			
		|||
            msg='No command found, please go to the platform details to add'
 | 
			
		||||
        )
 | 
			
		||||
    with SSHClient(module) as client:
 | 
			
		||||
        output, err_msg = client.execute(commands, answers)
 | 
			
		||||
        __, err_msg = client.execute(commands, answers)
 | 
			
		||||
        if err_msg:
 | 
			
		||||
            module.fail_json(
 | 
			
		||||
                msg='There was a problem executing the command: %s' % err_msg
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -116,7 +116,7 @@ def main():
 | 
			
		|||
 | 
			
		||||
    try:
 | 
			
		||||
        client.close()
 | 
			
		||||
    except Exception:
 | 
			
		||||
    except Exception: # noqa
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    return module.exit_json(**result)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,14 +7,44 @@ __metaclass__ = type
 | 
			
		|||
DOCUMENTATION = '''
 | 
			
		||||
---
 | 
			
		||||
module: custom_rdp_ping
 | 
			
		||||
short_description: Use rdp to probe whether an asset is connectable
 | 
			
		||||
short_description: Use RDP to probe whether an asset is connectable.
 | 
			
		||||
description:
 | 
			
		||||
    - Use rdp to probe whether an asset is connectable
 | 
			
		||||
    - Use RDP to probe whether an asset is connectable.
 | 
			
		||||
options:
 | 
			
		||||
    login_host:
 | 
			
		||||
        description: Target host to connect.
 | 
			
		||||
        type: str
 | 
			
		||||
        required: False
 | 
			
		||||
        default: localhost
 | 
			
		||||
    login_port:
 | 
			
		||||
        description: Target port to connect.
 | 
			
		||||
        type: int
 | 
			
		||||
        required: False
 | 
			
		||||
        default: 22
 | 
			
		||||
    login_user:
 | 
			
		||||
        description: Login user for the connection.
 | 
			
		||||
        type: str
 | 
			
		||||
        required: False
 | 
			
		||||
        default: root
 | 
			
		||||
    login_password:
 | 
			
		||||
        description: Login password.
 | 
			
		||||
        type: str
 | 
			
		||||
        required: False
 | 
			
		||||
        no_log: True
 | 
			
		||||
    login_secret_type:
 | 
			
		||||
        description: Authentication method.
 | 
			
		||||
        type: str
 | 
			
		||||
        required: False
 | 
			
		||||
        default: password
 | 
			
		||||
    gateway_args:
 | 
			
		||||
        description: Arguments for setting up an SSH tunnel.
 | 
			
		||||
        type: dict
 | 
			
		||||
        required: False
 | 
			
		||||
        default: null
 | 
			
		||||
'''
 | 
			
		||||
 | 
			
		||||
EXAMPLES = '''
 | 
			
		||||
- name: >
 | 
			
		||||
    Ping asset server.
 | 
			
		||||
- name: Ping asset server using RDP.
 | 
			
		||||
  custom_rdp_ping:
 | 
			
		||||
    login_host: 127.0.0.1
 | 
			
		||||
    login_port: 3389
 | 
			
		||||
| 
						 | 
				
			
			@ -24,12 +54,12 @@ EXAMPLES = '''
 | 
			
		|||
 | 
			
		||||
RETURN = '''
 | 
			
		||||
is_available:
 | 
			
		||||
  description: Windows server availability.
 | 
			
		||||
  description: Indicates if the Windows asset is available.
 | 
			
		||||
  returned: always
 | 
			
		||||
  type: bool
 | 
			
		||||
  sample: true
 | 
			
		||||
conn_err_msg:
 | 
			
		||||
  description: Connection error message.
 | 
			
		||||
  description: Connection error message (if any).
 | 
			
		||||
  returned: always
 | 
			
		||||
  type: str
 | 
			
		||||
  sample: ''
 | 
			
		||||
| 
						 | 
				
			
			@ -41,11 +71,6 @@ from sshtunnel import SSHTunnelForwarder
 | 
			
		|||
from ansible.module_utils.basic import AnsibleModule
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# =========================================
 | 
			
		||||
# Module execution.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def common_argument_spec():
 | 
			
		||||
    options = dict(
 | 
			
		||||
        login_host=dict(type='str', required=False, default='localhost'),
 | 
			
		||||
| 
						 | 
				
			
			@ -67,13 +92,12 @@ class RDPConnectionManager:
 | 
			
		|||
        self.result_queue = multiprocessing.Queue()
 | 
			
		||||
 | 
			
		||||
    def build_connection_details(self):
 | 
			
		||||
        connection_details = {
 | 
			
		||||
        return {
 | 
			
		||||
            'hostname': self.params['login_host'],
 | 
			
		||||
            'port': self.params['login_port'],
 | 
			
		||||
            'username': self.params['username'],
 | 
			
		||||
            'password': self.params['password']
 | 
			
		||||
            'username': self.params['login_user'],
 | 
			
		||||
            'password': self.params['login_password']
 | 
			
		||||
        }
 | 
			
		||||
        return connection_details
 | 
			
		||||
 | 
			
		||||
    def setup_ssh_tunnel(self):
 | 
			
		||||
        gateway_args = self.params['gateway_args'] or {}
 | 
			
		||||
| 
						 | 
				
			
			@ -90,8 +114,8 @@ class RDPConnectionManager:
 | 
			
		|||
                self.connection_details['port']
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        tunnel.start()
 | 
			
		||||
 | 
			
		||||
        self.connection_details['hostname'] = '127.0.0.1'
 | 
			
		||||
        self.connection_details['port'] = tunnel.local_bind_port
 | 
			
		||||
        self.ssh_tunnel = tunnel
 | 
			
		||||
| 
						 | 
				
			
			@ -107,13 +131,23 @@ class RDPConnectionManager:
 | 
			
		|||
        self.close_ssh_tunnel()
 | 
			
		||||
 | 
			
		||||
    def check_rdp_connectivity(self):
 | 
			
		||||
        connect_params = list(self.connection_details.values()) + ['', 0]
 | 
			
		||||
        is_reachable = pyfreerdp.check_connectivity(*connect_params)
 | 
			
		||||
        connect_params = [
 | 
			
		||||
            self.connection_details['hostname'],
 | 
			
		||||
            self.connection_details['port'],
 | 
			
		||||
            self.connection_details['username'],
 | 
			
		||||
            self.connection_details['password'],
 | 
			
		||||
            '',  # extra parameter (if needed)
 | 
			
		||||
            0    # timeout (if needed)
 | 
			
		||||
        ]
 | 
			
		||||
        try:
 | 
			
		||||
            is_reachable = pyfreerdp.check_connectivity(*connect_params)
 | 
			
		||||
        except Exception as ex:
 | 
			
		||||
            is_reachable = False
 | 
			
		||||
        self.result_queue.put(is_reachable)
 | 
			
		||||
 | 
			
		||||
    def attempt_connection(self):
 | 
			
		||||
        if self.params['login_secret_type'] != 'password':
 | 
			
		||||
            error_message = f'unsupported authentication method: {self.params["login_secret_type"]}'
 | 
			
		||||
            error_message = f"Unsupported authentication method: {self.params['login_secret_type']}"
 | 
			
		||||
            return False, error_message
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
| 
						 | 
				
			
			@ -138,17 +172,21 @@ class RDPConnectionManager:
 | 
			
		|||
def main():
 | 
			
		||||
    argument_spec = common_argument_spec()
 | 
			
		||||
    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
 | 
			
		||||
    result = {'changed': False}
 | 
			
		||||
    module_params = module.params
 | 
			
		||||
    rdp_manager = RDPConnectionManager(module_params)
 | 
			
		||||
    rdp_manager = RDPConnectionManager(module.params)
 | 
			
		||||
    is_available, error_message = rdp_manager.attempt_connection()
 | 
			
		||||
    result['is_available'] = is_available
 | 
			
		||||
 | 
			
		||||
    # Prepare the result structure.
 | 
			
		||||
    result = {
 | 
			
		||||
        'changed': False,
 | 
			
		||||
        'is_available': is_available,
 | 
			
		||||
        'conn_err_msg': error_message
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if not is_available:
 | 
			
		||||
        module.fail_json(msg=f'Unable to connect to asset: {error_message}')
 | 
			
		||||
 | 
			
		||||
    return module.exit_json(**result)
 | 
			
		||||
        module.fail_json(msg=f"Unable to connect to asset: {error_message}", **result)
 | 
			
		||||
    else:
 | 
			
		||||
        module.exit_json(**result)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    main()
 | 
			
		||||
    main()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,18 +4,35 @@ from __future__ import absolute_import, division, print_function
 | 
			
		|||
 | 
			
		||||
__metaclass__ = type
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DOCUMENTATION = '''
 | 
			
		||||
---
 | 
			
		||||
module: ssh_ping
 | 
			
		||||
short_description: Use ssh to probe whether an asset is connectable
 | 
			
		||||
description:
 | 
			
		||||
    - Use ssh to probe whether an asset is connectable
 | 
			
		||||
    - Use ssh to probe whether an asset is connectable.
 | 
			
		||||
options:
 | 
			
		||||
    login_host:
 | 
			
		||||
        description: The target host to connect.
 | 
			
		||||
        type: str
 | 
			
		||||
        required: True
 | 
			
		||||
    login_port:
 | 
			
		||||
        description: The port on the target host.
 | 
			
		||||
        type: int
 | 
			
		||||
        required: False
 | 
			
		||||
        default: 22
 | 
			
		||||
    login_user:
 | 
			
		||||
        description: The username for the SSH connection.
 | 
			
		||||
        type: str
 | 
			
		||||
        required: True
 | 
			
		||||
    login_password:
 | 
			
		||||
        description: The password for the SSH connection.
 | 
			
		||||
        type: str
 | 
			
		||||
        required: True
 | 
			
		||||
        no_log: True
 | 
			
		||||
'''
 | 
			
		||||
 | 
			
		||||
EXAMPLES = '''
 | 
			
		||||
- name: >
 | 
			
		||||
    Ping asset server.
 | 
			
		||||
- name: Ping asset server using SSH.
 | 
			
		||||
  ssh_ping:
 | 
			
		||||
    login_host: 127.0.0.1
 | 
			
		||||
    login_port: 22
 | 
			
		||||
| 
						 | 
				
			
			@ -25,36 +42,27 @@ EXAMPLES = '''
 | 
			
		|||
 | 
			
		||||
RETURN = '''
 | 
			
		||||
is_available:
 | 
			
		||||
  description: Ping server availability.
 | 
			
		||||
  description: Indicate whether the target server is reachable via SSH.
 | 
			
		||||
  returned: always
 | 
			
		||||
  type: bool
 | 
			
		||||
  sample: true
 | 
			
		||||
'''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from ansible.module_utils.basic import AnsibleModule
 | 
			
		||||
 | 
			
		||||
from libs.ansible.modules_utils.remote_client import (
 | 
			
		||||
    SSHClient, common_argument_spec
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# =========================================
 | 
			
		||||
# Module execution.
 | 
			
		||||
#
 | 
			
		||||
from libs.ansible.modules_utils.remote_client import SSHClient, common_argument_spec
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    options = common_argument_spec()
 | 
			
		||||
    module = AnsibleModule(argument_spec=options, supports_check_mode=True,)
 | 
			
		||||
    module = AnsibleModule(argument_spec=options, supports_check_mode=True)
 | 
			
		||||
 | 
			
		||||
    result = {'changed': False, 'is_available': False}
 | 
			
		||||
 | 
			
		||||
    result = {
 | 
			
		||||
        'changed': False, 'is_available': False
 | 
			
		||||
    }
 | 
			
		||||
    with SSHClient(module) as client:
 | 
			
		||||
        client.connect()
 | 
			
		||||
 | 
			
		||||
    result['is_available'] = True
 | 
			
		||||
    return module.exit_json(**result)
 | 
			
		||||
    module.exit_json(**result)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,55 +1,25 @@
 | 
			
		|||
import re
 | 
			
		||||
import signal
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
import paramiko
 | 
			
		||||
 | 
			
		||||
from functools import wraps
 | 
			
		||||
 | 
			
		||||
import paramiko
 | 
			
		||||
from sshtunnel import SSHTunnelForwarder
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DEFAULT_RE = '.*'
 | 
			
		||||
SU_PROMPT_LOCALIZATIONS = [
 | 
			
		||||
        'Password',
 | 
			
		||||
        '암호',
 | 
			
		||||
        'パスワード',
 | 
			
		||||
        'Adgangskode',
 | 
			
		||||
        'Contraseña',
 | 
			
		||||
        'Contrasenya',
 | 
			
		||||
        'Hasło',
 | 
			
		||||
        'Heslo',
 | 
			
		||||
        'Jelszó',
 | 
			
		||||
        'Lösenord',
 | 
			
		||||
        'Mật khẩu',
 | 
			
		||||
        'Mot de passe',
 | 
			
		||||
        'Parola',
 | 
			
		||||
        'Parool',
 | 
			
		||||
        'Pasahitza',
 | 
			
		||||
        'Passord',
 | 
			
		||||
        'Passwort',
 | 
			
		||||
        'Salasana',
 | 
			
		||||
        'Sandi',
 | 
			
		||||
        'Senha',
 | 
			
		||||
        'Wachtwoord',
 | 
			
		||||
        'ססמה',
 | 
			
		||||
        'Лозинка',
 | 
			
		||||
        'Парола',
 | 
			
		||||
        'Пароль',
 | 
			
		||||
        'गुप्तशब्द',
 | 
			
		||||
        'शब्दकूट',
 | 
			
		||||
        'సంకేతపదము',
 | 
			
		||||
        'හස්පදය',
 | 
			
		||||
        '密码',
 | 
			
		||||
        '密碼',
 | 
			
		||||
        '口令',
 | 
			
		||||
    ]
 | 
			
		||||
    'Password', '암호', 'パスワード', 'Adgangskode', 'Contraseña', 'Contrasenya',
 | 
			
		||||
    'Hasło', 'Heslo', 'Jelszó', 'Lösenord', 'Mật khẩu', 'Mot de passe',
 | 
			
		||||
    'Parola', 'Parool', 'Pasahitza', 'Passord', 'Passwort', 'Salasana',
 | 
			
		||||
    'Sandi', 'Senha', 'Wachtwoord', 'ססמה', 'Лозинка', 'Парола', 'Пароль',
 | 
			
		||||
    'गुप्तशब्द', 'शब्दकूट', 'సంకేతపదము', 'හස්පදය', '密码', '密碼', '口令',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_become_prompt_re():
 | 
			
		||||
    b_password_string = "|".join((r'(\w+\'s )?' + p) for p in SU_PROMPT_LOCALIZATIONS)
 | 
			
		||||
    b_password_string = b_password_string + ' ?(:|:) ?'
 | 
			
		||||
    return re.compile(b_password_string, flags=re.IGNORECASE)
 | 
			
		||||
    pattern_segments = (r'(\w+\'s )?' + p for p in SU_PROMPT_LOCALIZATIONS)
 | 
			
		||||
    prompt_pattern = "|".join(pattern_segments) + r' ?(:|:) ?'
 | 
			
		||||
    return re.compile(prompt_pattern, flags=re.IGNORECASE)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
become_prompt_re = get_become_prompt_re()
 | 
			
		||||
| 
						 | 
				
			
			@ -88,8 +58,8 @@ def raise_timeout(name=''):
 | 
			
		|||
            def handler(signum, frame):
 | 
			
		||||
                raise TimeoutError(f'{name} timed out, wait {timeout}s')
 | 
			
		||||
 | 
			
		||||
            timeout = getattr(self, 'timeout', 0)
 | 
			
		||||
            try:
 | 
			
		||||
                timeout = getattr(self, 'timeout', 0)
 | 
			
		||||
                if timeout > 0:
 | 
			
		||||
                    signal.signal(signal.SIGALRM, handler)
 | 
			
		||||
                    signal.alarm(timeout)
 | 
			
		||||
| 
						 | 
				
			
			@ -97,7 +67,9 @@ def raise_timeout(name=''):
 | 
			
		|||
            except Exception as error:
 | 
			
		||||
                signal.alarm(0)
 | 
			
		||||
                raise error
 | 
			
		||||
 | 
			
		||||
        return wrapper
 | 
			
		||||
 | 
			
		||||
    return decorate
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -122,8 +94,8 @@ class SSHClient:
 | 
			
		|||
        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
 | 
			
		||||
        self.connect_params = self.get_connect_params()
 | 
			
		||||
        self._channel = None
 | 
			
		||||
 | 
			
		||||
        self.buffer_size = 1024
 | 
			
		||||
        self.connect_params = self.get_connect_params()
 | 
			
		||||
        self.prompt = self.module.params['prompt']
 | 
			
		||||
        self.timeout = self.module.params['recv_timeout']
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -134,45 +106,54 @@ class SSHClient:
 | 
			
		|||
        return self._channel
 | 
			
		||||
 | 
			
		||||
    def get_connect_params(self):
 | 
			
		||||
        p = self.module.params
 | 
			
		||||
        params = {
 | 
			
		||||
            'allow_agent': False, 'look_for_keys': False,
 | 
			
		||||
            'hostname': self.module.params['login_host'],
 | 
			
		||||
            'port': self.module.params['login_port'],
 | 
			
		||||
            'key_filename': self.module.params['login_private_key_path'] or None
 | 
			
		||||
            'allow_agent': False,
 | 
			
		||||
            'look_for_keys': False,
 | 
			
		||||
            'hostname': p['login_host'],
 | 
			
		||||
            'port': p['login_port'],
 | 
			
		||||
            'key_filename': p['login_private_key_path'] or None
 | 
			
		||||
        }
 | 
			
		||||
        if self.module.params['become']:
 | 
			
		||||
            params['username'] = self.module.params['become_user']
 | 
			
		||||
            params['password'] = self.module.params['become_password']
 | 
			
		||||
            params['key_filename'] = self.module.params['become_private_key_path'] or None
 | 
			
		||||
 | 
			
		||||
        if p['become']:
 | 
			
		||||
            params['username'] = p['become_user']
 | 
			
		||||
            params['password'] = p['become_password']
 | 
			
		||||
            params['key_filename'] = p['become_private_key_path'] or None
 | 
			
		||||
        else:
 | 
			
		||||
            params['username'] = self.module.params['login_user']
 | 
			
		||||
            params['password'] = self.module.params['login_password']
 | 
			
		||||
            params['key_filename'] = self.module.params['login_private_key_path'] or None
 | 
			
		||||
        if self.module.params['old_ssh_version']:
 | 
			
		||||
            params['username'] = p['login_user']
 | 
			
		||||
            params['password'] = p['login_password']
 | 
			
		||||
            params['key_filename'] = p['login_private_key_path'] or None
 | 
			
		||||
 | 
			
		||||
        if p['old_ssh_version']:
 | 
			
		||||
            params['transport_factory'] = OldSSHTransport
 | 
			
		||||
 | 
			
		||||
        return params
 | 
			
		||||
 | 
			
		||||
    def switch_user(self):
 | 
			
		||||
        if not self.module.params['become']:
 | 
			
		||||
            return
 | 
			
		||||
        method = self.module.params['become_method']
 | 
			
		||||
        username = self.module.params['login_user']
 | 
			
		||||
        if method == 'sudo':
 | 
			
		||||
            switch_method = 'sudo su -'
 | 
			
		||||
            password = self.module.params['become_password']
 | 
			
		||||
        elif method == 'su':
 | 
			
		||||
            switch_method = 'su -'
 | 
			
		||||
            password = self.module.params['login_password']
 | 
			
		||||
        else:
 | 
			
		||||
            self.module.fail_json(msg='Become method %s not support' % method)
 | 
			
		||||
        p = self.module.params
 | 
			
		||||
        if not p['become']:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        __, e_msg = self.execute(
 | 
			
		||||
            [f'{switch_method} {username}', password, 'whoami'],
 | 
			
		||||
        method = p['become_method']
 | 
			
		||||
        username = p['login_user']
 | 
			
		||||
 | 
			
		||||
        if method == 'sudo':
 | 
			
		||||
            switch_cmd = 'sudo su -'
 | 
			
		||||
            pword = p['become_password']
 | 
			
		||||
        elif method == 'su':
 | 
			
		||||
            switch_cmd = 'su -'
 | 
			
		||||
            pword = p['login_password']
 | 
			
		||||
        else:
 | 
			
		||||
            self.module.fail_json(msg=f'Become method {method} not supported.')
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        # Expected to see a prompt, type the password, and check the username
 | 
			
		||||
        output, error = self.execute(
 | 
			
		||||
            [f'{switch_cmd} {username}', pword, 'whoami'],
 | 
			
		||||
            [become_prompt_re, DEFAULT_RE, username]
 | 
			
		||||
        )
 | 
			
		||||
        if e_msg:
 | 
			
		||||
            self.module.fail_json(msg='Become user %s failed.' % username)
 | 
			
		||||
        if error:
 | 
			
		||||
            self.module.fail_json(msg=f'Failed to become user {username}. Output: {output}')
 | 
			
		||||
 | 
			
		||||
    def connect(self):
 | 
			
		||||
        self.before_runner_start()
 | 
			
		||||
| 
						 | 
				
			
			@ -193,28 +174,32 @@ class SSHClient:
 | 
			
		|||
        return answers
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def __match(re_, content):
 | 
			
		||||
        re_pattern = re_
 | 
			
		||||
        if isinstance(re_, str):
 | 
			
		||||
            re_pattern = re.compile(re_, re.DOTALL | re.IGNORECASE)
 | 
			
		||||
        elif not isinstance(re_pattern, re.Pattern):
 | 
			
		||||
            raise ValueError(f'{re_} should be a regular expression')
 | 
			
		||||
        return bool(re_pattern.search(content))
 | 
			
		||||
    def __match(expression, content):
 | 
			
		||||
        if isinstance(expression, str):
 | 
			
		||||
            expression = re.compile(expression, re.DOTALL | re.IGNORECASE)
 | 
			
		||||
        elif not isinstance(expression, re.Pattern):
 | 
			
		||||
            raise ValueError(f'{expression} should be a regular expression')
 | 
			
		||||
 | 
			
		||||
        return bool(expression.search(content))
 | 
			
		||||
 | 
			
		||||
    @raise_timeout('Recv message')
 | 
			
		||||
    def _get_match_recv(self, answer_reg=DEFAULT_RE):
 | 
			
		||||
        last_output, output = '', ''
 | 
			
		||||
        buffer_str = ''
 | 
			
		||||
        prev_str = ''
 | 
			
		||||
 | 
			
		||||
        check_reg = self.prompt if answer_reg == DEFAULT_RE else answer_reg
 | 
			
		||||
        while True:
 | 
			
		||||
            if self.channel.recv_ready():
 | 
			
		||||
                recv = self.channel.recv(self.buffer_size).decode()
 | 
			
		||||
                output += recv
 | 
			
		||||
            if output and last_output != output:
 | 
			
		||||
                fin_reg = self.prompt if answer_reg == DEFAULT_RE else answer_reg
 | 
			
		||||
                if self.__match(fin_reg, output):
 | 
			
		||||
                chunk = self.channel.recv(self.buffer_size).decode('utf-8', 'replace')
 | 
			
		||||
                buffer_str += chunk
 | 
			
		||||
 | 
			
		||||
            if buffer_str and buffer_str != prev_str:
 | 
			
		||||
                if self.__match(check_reg, buffer_str):
 | 
			
		||||
                    break
 | 
			
		||||
            last_output = output
 | 
			
		||||
            prev_str = buffer_str
 | 
			
		||||
            time.sleep(0.01)
 | 
			
		||||
        return output
 | 
			
		||||
 | 
			
		||||
        return buffer_str
 | 
			
		||||
 | 
			
		||||
    @raise_timeout('Wait send message')
 | 
			
		||||
    def _check_send(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -223,38 +208,44 @@ class SSHClient:
 | 
			
		|||
        time.sleep(self.module.params['delay_time'])
 | 
			
		||||
 | 
			
		||||
    def execute(self, commands, answers=None):
 | 
			
		||||
        all_output, error_msg = '', ''
 | 
			
		||||
        combined_output = ''
 | 
			
		||||
        error_msg = ''
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            answers = self._fit_answers(commands, answers)
 | 
			
		||||
            for index, command in enumerate(commands):
 | 
			
		||||
            for cmd, ans_regex in zip(commands, answers):
 | 
			
		||||
                self._check_send()
 | 
			
		||||
                self.channel.send(command + '\n')
 | 
			
		||||
                all_output += f'{self._get_match_recv(answers[index])}\n'
 | 
			
		||||
                self.channel.send(cmd + '\n')
 | 
			
		||||
                combined_output += self._get_match_recv(ans_regex) + '\n'
 | 
			
		||||
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            error_msg = str(e)
 | 
			
		||||
        return all_output, error_msg
 | 
			
		||||
 | 
			
		||||
        return combined_output, error_msg
 | 
			
		||||
 | 
			
		||||
    def local_gateway_prepare(self):
 | 
			
		||||
        gateway_args = self.module.params['gateway_args'] or ''
 | 
			
		||||
        pattern = r"(?:sshpass -p ([^ ]+))?\s*ssh -o Port=(\d+)\s+-o StrictHostKeyChecking=no\s+([\w@]+)@([" \
 | 
			
		||||
                  r"\d.]+)\s+-W %h:%p -q(?: -i (.+))?'"
 | 
			
		||||
        pattern = (
 | 
			
		||||
            r"(?:sshpass -p ([^ ]+))?\s*ssh -o Port=(\d+)\s+-o StrictHostKeyChecking=no\s+"
 | 
			
		||||
            r"([\w@]+)@([\d.]+)\s+-W %h:%p -q(?: -i (.+))?'"
 | 
			
		||||
        )
 | 
			
		||||
        match = re.search(pattern, gateway_args)
 | 
			
		||||
 | 
			
		||||
        if not match:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        password, port, username, address, private_key_path = match.groups()
 | 
			
		||||
        password = password if password else None
 | 
			
		||||
        private_key_path = private_key_path if private_key_path else None
 | 
			
		||||
        remote_hostname = self.module.params['login_host']
 | 
			
		||||
        remote_port = self.module.params['login_port']
 | 
			
		||||
        password, port, username, remote_addr, key_path = match.groups()
 | 
			
		||||
        password = password or None
 | 
			
		||||
        key_path = key_path or None
 | 
			
		||||
 | 
			
		||||
        server = SSHTunnelForwarder(
 | 
			
		||||
            (address, int(port)),
 | 
			
		||||
            (remote_addr, int(port)),
 | 
			
		||||
            ssh_username=username,
 | 
			
		||||
            ssh_password=password,
 | 
			
		||||
            ssh_pkey=private_key_path,
 | 
			
		||||
            remote_bind_address=(remote_hostname, remote_port)
 | 
			
		||||
            ssh_pkey=key_path,
 | 
			
		||||
            remote_bind_address=(
 | 
			
		||||
                self.module.params['login_host'],
 | 
			
		||||
                self.module.params['login_port']
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        server.start()
 | 
			
		||||
| 
						 | 
				
			
			@ -263,11 +254,8 @@ class SSHClient:
 | 
			
		|||
        self.gateway_server = server
 | 
			
		||||
 | 
			
		||||
    def local_gateway_clean(self):
 | 
			
		||||
        gateway_server = self.gateway_server
 | 
			
		||||
        if not gateway_server:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        gateway_server.stop()
 | 
			
		||||
        if self.gateway_server:
 | 
			
		||||
            self.gateway_server.stop()
 | 
			
		||||
 | 
			
		||||
    def before_runner_start(self):
 | 
			
		||||
        self.local_gateway_prepare()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue