예제 #1
0
파일: helpers.py 프로젝트: ares/robottelo
def get_available_capsule_port(port_pool=None):
    """returns a list of unused ports dedicated for fake capsules
    This calls a fuser command on the server prompting for a port range. fuser
    commands returns a list of ports which have a PID assigned (a list of ports
    which are already used). This function then substracts unavailable ports
    from the other ones and returns one of available ones randomly.

    :param port_pool: A list of ports used for fake capsules (for RHEL7+: don't
        forget to set a correct selinux context before otherwise you'll get
        Connection Refused error)

    :return: Random available port from interval <9091, 9190>.
    :rtype: int
    """
    if port_pool is None:
        port_pool_range = settings.fake_capsules.port_range
        if type(port_pool_range) is tuple and len(port_pool_range) is 2:
            port_pool = range(int(port_pool_range[0]), int(port_pool_range[1]))
        else:
            raise TypeError(
                '''Expected type of port_range is a tuple of 2 elements,
                got {0} instead'''
                .format(type(port_pool_range))
            )
    # returns a list of strings
    fuser_cmd = ssh.command(
        'fuser -n tcp {{{0}..{1}}} 2>&1 | awk -F/ \'{{print$1}}\''
        .format(port_pool[0], port_pool[-1])
    )
    if fuser_cmd.stderr:
        raise CapsuleTunnelError(
            'Failed to create ssh tunnel: Error getting port status: {0}'
            .format(fuser_cmd.stderr)
        )
    # converts a List of strings to a List of integers
    try:
        print(fuser_cmd)
        used_ports = map(
            int,
            [val for val in fuser_cmd.stdout[:-1]
                if val != 'Cannot stat file ']
        )

    except ValueError:
        raise CapsuleTunnelError(
            'Failed parsing the port numbers from stdout: {0}'
            .format(fuser_cmd.stdout[:-1])
        )
    try:
        # take the list of available ports and return randomly selected one
        return random.choice(
            [port for port in port_pool if port not in used_ports]
        )
    except IndexError:
        raise CapsuleTunnelError(
            'Failed to create ssh tunnel: No more ports available for mapping'
        )
예제 #2
0
    def get_available_capsule_port(self, port_pool=None):
        """returns a list of unused ports dedicated for fake capsules
        This calls an ss command on the server prompting for a port range. ss
        returns a list of ports which have a PID assigned (a list of ports
        which are already used). This function then substracts unavailable ports
        from the other ones and returns one of available ones randomly.

        :param port_pool: A list of ports used for fake capsules (for RHEL7+: don't
            forget to set a correct selinux context before otherwise you'll get
            Connection Refused error)

        :return: Random available port from interval <9091, 9190>.
        :rtype: int
        """
        if port_pool is None:
            from robottelo.config import settings

            port_pool_range = settings.fake_capsules.port_range
            if isinstance(port_pool_range, str):
                port_pool_range = tuple(port_pool_range.split('-'))
            if isinstance(port_pool_range, tuple) and len(port_pool_range) == 2:
                port_pool = range(int(port_pool_range[0]), int(port_pool_range[1]))
            else:
                raise TypeError(
                    'Expected type of port_range is a tuple of 2 elements,'
                    f'got {type(port_pool_range)} instead'
                )
        # returns a list of strings
        ss_cmd = self.execute(
            f"ss -tnaH sport ge {port_pool[0]} sport le {port_pool[-1]}"
            " | awk '{n=split($4, p, \":\"); print p[n]}' | sort -u"
        )
        if ss_cmd.stderr[1]:
            raise CapsuleTunnelError(
                f'Failed to create ssh tunnel: Error getting port status: {ss_cmd.stderr}'
            )
        # converts a List of strings to a List of integers
        try:
            used_ports = map(
                int, [val for val in ss_cmd.stdout.splitlines()[:-1] if val != 'Cannot stat file ']
            )

        except ValueError:
            raise CapsuleTunnelError(
                f'Failed parsing the port numbers from stdout: {ss_cmd.stdout.splitlines()[:-1]}'
            )
        try:
            # take the list of available ports and return randomly selected one
            return random.choice([port for port in port_pool if port not in used_ports])
        except IndexError:
            raise CapsuleTunnelError(
                'Failed to create ssh tunnel: No more ports available for mapping'
            )
예제 #3
0
def default_url_on_new_port(oldport, newport):
    """Creates context where the default capsule is forwarded on a new port

    :param int oldport: Port to be forwarded.
    :param int newport: New port to be used to forward `oldport`.

    :return: A string containing the new capsule URL with port.
    :rtype: str

    """
    domain = settings.server.hostname

    with ssh.get_connection() as connection:
        command = f'ncat -kl -p {newport} -c "ncat {domain} {oldport}"'
        logger.debug(f'Creating tunnel: {command}')
        transport = connection.get_transport()
        channel = transport.open_session()
        channel.get_pty()
        channel.exec_command(command)
        # if exit_status appears until command_timeout, throw error
        if channel.exit_status_ready():
            if channel.recv_exit_status() != 0:
                stderr = ''
                while channel.recv_stderr_ready():
                    stderr += channel.recv_stderr(1)
                logger.debug(f'Tunnel failed: {stderr}')
                # Something failed, so raise an exception.
                raise CapsuleTunnelError(stderr)
        yield f'https://{domain}:{newport}'
예제 #4
0
def default_url_on_new_port(oldport, newport):
    """Creates context where the default capsule is forwarded on a new port

    :param int oldport: Port to be forwarded.
    :param int newport: New port to be used to forward `oldport`.

    :return: A string containing the new capsule URL with port.
    :rtype: str

    """
    logger = logging.getLogger('robottelo')
    domain = settings.server.hostname

    with ssh.get_connection() as connection:
        command = (u'ncat -kl -p {0} -c "ncat {1} {2}"').format(
            newport, domain, oldport)
        logger.debug('Creating tunnel: {0}'.format(command))
        transport = connection.get_transport()
        channel = transport.open_session()
        channel.get_pty()
        channel.exec_command(command)
        # if exit_status appears until command_timeout, throw error
        if channel.exit_status_ready():
            if channel.recv_exit_status() != 0:
                stderr = u''
                while channel.recv_stderr_ready():
                    stderr += channel.recv_stderr(1)
                logger.debug('Tunnel failed: {0}'.format(stderr))
                # Something failed, so raise an exception.
                raise CapsuleTunnelError(stderr)
        yield 'https://{0}:{1}'.format(domain, newport)
예제 #5
0
def default_url_on_new_port(oldport, newport):
    """Creates context where the default capsule is forwarded on a new port

    :param int oldport: Port to be forwarded.
    :param int newport: New port to be used to forward `oldport`.

    :return: A string containing the new capsule URL with port.
    :rtype: str

    """
    domain = settings.server.hostname

    client = ssh.get_client()
    pre_ncat_procs = client.execute('pgrep ncat').stdout.splitlines()

    with client.session.shell() as channel:
        # if ncat isn't backgrounded, it prevents the channel from closing
        command = f'ncat -kl -p {newport} -c "ncat {domain} {oldport}" &'
        # broker 0.1.25 makes these debug messages redundant
        logger.debug(f'Creating tunnel: {command}')
        channel.send(command)
        post_ncat_procs = client.execute('pgrep ncat').stdout.splitlines()
        ncat_pid = set(post_ncat_procs).difference(set(pre_ncat_procs))
        if not len(ncat_pid):
            stderr = channel.get_exit_status()[1]
            logger.debug(f'Tunnel failed: {stderr}')
            # Something failed, so raise an exception.
            raise CapsuleTunnelError(f'Starting ncat failed: {stderr}')
        forward_url = f'https://{domain}:{newport}'
        logger.debug(f'Yielding capsule forward port url: {forward_url}')
        try:
            yield forward_url
        finally:
            logger.debug(f'Killing ncat pid: {ncat_pid}')
            client.execute(f'kill {ncat_pid.pop()}')