Esempio n. 1
0
    def __init__(self, socket_dir=None,
                 socket_file=None,
                 retry=2,
                 retry_interval=2):

        self._hap_processes = []
        socket_files = []

        if socket_dir:
            if not os.path.exists(socket_dir):
                raise ValueError("socket directory does not exist "
                                 "{}".format(socket_dir))

            for _file in glob.glob(os.path.join(socket_dir, '*')):
                if is_unix_socket(_file) and connected_socket(_file):
                    socket_files.append(_file)
        elif (socket_file and is_unix_socket(socket_file) and
              connected_socket(socket_file)):
            socket_files.append(os.path.realpath(socket_file))
        else:
            raise ValueError("UNIX socket file was not set")

        if not socket_files:
            raise ValueError("No valid UNIX socket file was found, directory: "
                             "{} file: {}".format(socket_dir, socket_file))

        for so_file in socket_files:
            self._hap_processes.append(
                _HAProxyProcess(so_file, retry, retry_interval)
            )
Esempio n. 2
0
    def __init__(self,
                 socket_dir=None,
                 socket_file=None,
                 retry=2,
                 retry_interval=2):

        self._hap_processes = []
        socket_files = []

        if socket_dir:
            if not os.path.exists(socket_dir):
                raise ValueError("socket directory does not exist "
                                 "{}".format(socket_dir))

            for _file in glob.glob(os.path.join(socket_dir, '*')):
                if is_unix_socket(_file) and connected_socket(_file):
                    socket_files.append(_file)
        elif (socket_file and is_unix_socket(socket_file)
              and connected_socket(socket_file)):
            socket_files.append(os.path.realpath(socket_file))
        else:
            raise ValueError("UNIX socket file was not set")

        if not socket_files:
            raise ValueError("No valid UNIX socket file was found, directory: "
                             "{} file: {}".format(socket_dir, socket_file))

        for so_file in socket_files:
            self._hap_processes.append(
                _HAProxyProcess(so_file, retry, retry_interval))
Esempio n. 3
0
    def command(self, command, full_output=False):
        """Send a command to HAProxy over UNIX stats socket.

        Newline character returned from haproxy is stripped off.

        :param command: A valid command to execute
        :type command: string
        :param full_output: (optional) Return all output, by default
          returns only the 1st line of the output
        :type full_output: ``bool``
        :return: 1st line of the output or the whole output as a list
        :rtype: ``string`` or ``list`` if full_output is True
        """
        data = []  # hold data returned from socket
        raised = None  # hold possible exception raised during connect phase
        attempt = 0  # times to attempt to connect after a connection failure
        if self.retry == 0:
            # 0 means retry indefinitely
            attempt = -1
        elif self.retry is None:
            # None means don't retry
            attempt = 1
        else:
            # any other value means retry N times
            attempt = self.retry + 1
        while attempt != 0:
            try:
                unix_socket = None
                tcpsocket = None
                if is_unix_socket(self.sock):
                    unix_socket = socket.socket(socket.AF_UNIX,
                                                socket.SOCK_STREAM)
                    unix_socket.settimeout(0.5)
                    unix_socket.connect(self.sock)
                    unix_socket.send(six.b(command + '\n'))
                    file_handle = unix_socket.makefile()
                    data = file_handle.read().splitlines()

                else:
                    tcpsocket = socket.socket(socket.AF_INET,
                                              socket.SOCK_STREAM)
                    parts = urisplit(self.sock)
                    if type(parts.gethost()
                            ) == ipaddress.IPv4Address or hostname_resolves(
                                parts.gethost()):
                        tcpsocket.settimeout(2.0)
                        tcpsocket.connect((parts.gethost(), parts.getport()))
                        tcpsocket.send(six.b(command + '\n'))
                        file_handle = tcpsocket.makefile()
                        data = file_handle.read().splitlines()
                    else:
                        raise ValueError(
                            "URI is neither a valid IPAddess nor a resolvable hostname"
                        )

                # I haven't seen a case where a running process which holds a
                # UNIX socket will take more than few nanoseconds to accept a
                # connection. But, I have seen cases where it takes ~0.5secs
                # to get a respone from the socket. Thus I hard-code a timeout
                # of 0.5ms
                # TODO: consider having a configuration file for it
            except socket.timeout:
                raised = SocketTimeout(sock=self.sock)
            except OSError as exc:
                # while stress testing HAProxy and querying for all frontend
                # metrics I sometimes get:
                # OSError: [Errno 106] Transport endpoint is already connected
                # catch this one only and reraise it withour exception
                if exc.errno == errno.EISCONN:
                    raised = SocketTransportError(sock=self.sock)
                elif exc.errno == errno.ECONNREFUSED:
                    raised = SocketConnectionError(self.sock)
                else:
                    # for the rest of OSError exceptions just reraise them
                    raised = exc
            else:
                # HAProxy always send an empty string at the end
                # we remove it as it adds noise for things like ACL/MAP and etc
                # We only do that when we get more than 1 line, which only
                # happens when we ask for ACL/MAP/etc and not for giving cmds
                # such as disable/enable server
                if len(data) > 1 and data[-1] == '':
                    data.pop()
                # make sure possible previous errors are cleared
                raised = None
                # get out from the retry loop
                break
            finally:
                if unix_socket:
                    unix_socket.close()
                elif tcpsocket:
                    tcpsocket.close()
                if raised:
                    time.sleep(self.retry_interval)

            attempt -= 1

        if raised:
            raise raised
        elif data:
            if full_output:
                return data
            else:
                return data[0]
        else:
            raise ValueError("no data returned from socket {}".format(
                self.socket_file))