Skip to content

Commit

Permalink
Merge pull request truenas#21 from truenas/macos-fix
Browse files Browse the repository at this point in the history
NAS-133037 / 25.04 / make api_client work on macos
  • Loading branch information
yocalebo authored Dec 11, 2024
2 parents 92f9302 + 03abdf2 commit 3576b3c
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 33 deletions.
18 changes: 2 additions & 16 deletions truenas_api_client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
from .exc import ReserveFDException, ClientException, ErrnoMixin, ValidationErrors, CallTimeout
from .legacy import LegacyClient
from .jsonrpc import CollectionUpdateParams, ErrorObj, JobFields, JSONRPCError, JSONRPCMessage, TruenasError
from .utils import MIDDLEWARE_RUN_DIR, ProgressBar, undefined, UndefinedType
from .utils import MIDDLEWARE_RUN_DIR, ProgressBar, undefined, UndefinedType, set_socket_options

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -218,21 +218,7 @@ def _on_open(self, app):
"""
# TCP keepalive settings don't apply to local unix sockets
if 'ws+unix' not in self.url:
# enable keepalives on the socket
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)

# If the other node panics then the socket will
# remain open and we'll have to wait until the
# TCP timeout value expires (60 seconds default).
# To account for this:
# 1. if the socket is idle for 1 seconds
# 2. send a keepalive packet every 1 second
# 3. for a maximum up to 5 times
#
# after 5 times (5 seconds of no response), the socket will be closed
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 1)
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 1)
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 5)
set_socket_options(self.socket)

# if we're able to connect put socket in blocking mode
# until all operations complete or error is raised
Expand Down
19 changes: 2 additions & 17 deletions truenas_api_client/legacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@
from . import ejson as json
from .config import CALL_TIMEOUT
from .exc import ReserveFDException, ClientException, ValidationErrors, CallTimeout
from .utils import MIDDLEWARE_RUN_DIR, undefined, UndefinedType
from .utils import MIDDLEWARE_RUN_DIR, undefined, UndefinedType, set_socket_options

logger = logging.getLogger(__name__)


class WSClient:
def __init__(self, url, *, client, reserved_ports=False, verify_ssl=True):
self.url = url
Expand Down Expand Up @@ -104,21 +103,7 @@ def _bind_to_reserved_port(self):
def _on_open(self, app):
# TCP keepalive settings don't apply to local unix sockets
if 'ws+unix' not in self.url:
# enable keepalives on the socket
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)

# If the other node panics then the socket will
# remain open and we'll have to wait until the
# TCP timeout value expires (60 seconds default).
# To account for this:
# 1. if the socket is idle for 1 seconds
# 2. send a keepalive packet every 1 second
# 3. for a maximum up to 5 times
#
# after 5 times (5 seconds of no response), the socket will be closed
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 1)
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 1)
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 5)
set_socket_options(self.socket)

# if we're able to connect put socket in blocking mode
# until all operations complete or error is raised
Expand Down
28 changes: 28 additions & 0 deletions truenas_api_client/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
undefined: A dummy object similar in purpose to `None` that indicates an unset variable.
"""
import socket
import sys

from typing import Any, final, Mapping
Expand Down Expand Up @@ -131,3 +132,30 @@ def __exit__(self, typ, value, traceback):
if self.used_flag:
self.draw()
self.write_stream.write('\n')


def set_socket_options(socobj):
plat = sys.platform
if plat not in ('win32', 'linux', 'freebsd', 'darwin'):
raise RuntimeError('Unsupported platform')

# enable keepalives on the socket
socobj.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)

# If the other node panics then the socket will
# remain open and we'll have to wait until the
# TCP timeout value expires (60 seconds default).
# To account for this:
# 1. if the socket is idle for 1 seconds
# 2. send a keepalive packet every 1 second
# 3. for a maximum up to 5 times
#
# after 5 times (5 seconds of no response), the socket will be closed
if plat in ('linux', 'freebsd', 'win32'):
socobj.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 1) # pytype: disable=module-attr

else:
socobj.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPALIVE, 1) # pytype: disable=module-attr

socobj.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 1)
socobj.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 5)

0 comments on commit 3576b3c

Please sign in to comment.