Skip to content

Commit

Permalink
[NBS, Filestore]: Add unix socket path to blockstore and filestore cl…
Browse files Browse the repository at this point in the history
…ients (#2535)

* Add a server-unix-socket-path argument for blockstore and filestore clients.
* Add option to listen on the unix socket in the filestore recipe.
* Add tests which check that the unix socket server does not require authorization.
  • Loading branch information
jkuradobery authored Nov 22, 2024
1 parent 1a345db commit 0c825cc
Show file tree
Hide file tree
Showing 12 changed files with 94 additions and 6 deletions.
1 change: 1 addition & 0 deletions cloud/blockstore/apps/client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* ```--input``` - path to a file from which request data should be read: buffers for ```WriteBlocks``` request or whole request protobuf if ```--proto``` option is specified
* ```--output``` - path to a file where response data should be written: buffers for ```ReadBlocks``` request or whole response protobuf if ```--proto``` option is specified
* free argument: the name of request to execute; can be written either in camel case (i.e. ```WriteBlocks```) or as a single lowercase or uppercase word (i.e. ```writeblocks```) or with words separated by hyphens or underscores (i.e. ```write-blocks```).
* ```--server-unix-socket-path``` - path to a socket on which the NBS server contacted by the client is listening; not mandatory

## Options for particular commands

Expand Down
7 changes: 7 additions & 0 deletions cloud/blockstore/apps/client/lib/command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ TCommand::TCommand(IBlockStorePtr client)
.RequiredArgument("NUM")
.StoreResult(&SecurePort);

Opts.AddLongOption("server-unix-socket-path")
.RequiredArgument("STR")
.StoreResult(&ServerUnixSocketPath);

Opts.AddLongOption("endpoint-proxy-host", "endpoint proxy host")
.RequiredArgument("STR")
.StoreResult(&EndpointProxyHost);
Expand Down Expand Up @@ -627,6 +631,9 @@ void TCommand::InitClientConfig()
if (SecurePort) {
clientConfig.SetSecurePort(SecurePort);
}
if (ServerUnixSocketPath){
clientConfig.SetUnixSocketPath(ServerUnixSocketPath);
}
if (clientConfig.GetHost() == "localhost" &&
clientConfig.GetSecurePort() != 0)
{
Expand Down
1 change: 1 addition & 0 deletions cloud/blockstore/apps/client/lib/command.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class TCommand
TString Host;
ui32 InsecurePort = 0;
ui32 SecurePort = 0;
TString ServerUnixSocketPath;
bool SkipCertVerification = false;

TString EndpointProxyHost;
Expand Down
43 changes: 38 additions & 5 deletions cloud/blockstore/tests/loadtest/local-auth/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import yatest.common as common

from pathlib import Path
from tempfile import TemporaryDirectory

from google.protobuf.text_format import MessageToString

Expand Down Expand Up @@ -90,12 +91,21 @@ def create_client_config():
class TestFixture:
__binary_path = common.binary_path("cloud/blockstore/apps/client/blockstore-client")

def __init__(self, access_service_type=AccessService, folder_id="test_folder_id"):
server = create_server_app_config()
def __init__(
self,
access_service_type=AccessService,
folder_id="test_folder_id",
server_unix_socket_path: str | None = None,
):
server_app_config = create_server_app_config()
if server_unix_socket_path is not None:
server_app_config.ServerConfig.UnixSocketPath = server_unix_socket_path
server_app_config.ServerConfig.AllowAllRequestsViaUDS = True
self.server_unix_socket_path = server_unix_socket_path
storage = create_storage_service_config(folder_id)
self.__local_load_test = LocalLoadTest(
"",
server_app_config=server,
server_app_config=server_app_config,
enable_access_service=True,
storage_config_patches=[storage],
enable_tls=True,
Expand All @@ -116,8 +126,14 @@ def __exit__(self, exc_type, exc_val, exc_tb):
self.__local_load_test.tear_down()

def run(self, *args, **kwargs):
args = [self.__binary_path, *args, "--config", str(self.__client_config_path)]

args = [
self.__binary_path,
*args,
"--config",
str(self.__client_config_path),
]
if self.server_unix_socket_path is not None:
args += ["--server-unix-socket-path", self.server_unix_socket_path]
env = {}
if self.__auth_token is not None:
env['IAM_TOKEN'] = self.__auth_token
Expand Down Expand Up @@ -220,3 +236,20 @@ def test_new_auth_unknown_subject():
result = env.create_volume()
assert result.returncode != 0
assert json.loads(result.stdout)["Error"]["CodeString"] == "E_UNAUTHORIZED"


def test_unix_socket_does_not_require_auth():
with TemporaryDirectory(dir="/tmp") as temp_dir:
server_unix_socket_path = str(Path(temp_dir) / "nbs.sock")
with TestFixture(NewAccessService, server_unix_socket_path=server_unix_socket_path) as env:
token = "some_token"
env.access_service.create_account(
"test_user",
token,
is_unknown_subject=True,
permissions=[
{"permission": "nbsInternal.disks.create", "resource": env.folder_id},
],
)
result = env.create_volume()
assert result.returncode == 0
7 changes: 7 additions & 0 deletions cloud/filestore/apps/client/lib/command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ TCommand::TCommand()
.RequiredArgument("NUM")
.StoreResult(&SecurePort);

Opts.AddLongOption("server-unix-socket-path")
.RequiredArgument("STR")
.StoreResult(&ServerUnixSocketPath);

Opts.AddLongOption("skip-cert-verification", "skip server certificate verification")
.StoreTrue(&SkipCertVerification);

Expand Down Expand Up @@ -197,6 +201,9 @@ void TCommand::Init()
if (SecurePort) {
config.SetSecurePort(SecurePort);
}
if (ServerUnixSocketPath){
config.SetUnixSocketPath(ServerUnixSocketPath);
}
if (config.GetHost() == "localhost" &&
config.GetSecurePort() != 0)
{
Expand Down
1 change: 1 addition & 0 deletions cloud/filestore/apps/client/lib/command.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class TCommand
TString ServerAddress;
ui32 ServerPort = 0;
ui32 SecurePort = 0;
TString ServerUnixSocketPath;
bool SkipCertVerification = false;
TString IamTokenFile;
TString ConfigFile;
Expand Down
6 changes: 5 additions & 1 deletion cloud/filestore/tests/auth/lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ def __init__(self):
client_config.ClientConfig.SecurePort = int(self.__port)
self.__client_config_path.write_text(MessageToString(client_config))

def get_client(self, auth_token):
def get_client(self, auth_token, use_unix_socket=False):
# auth_token MUST be a non-empty string; otherwise, the client will look
# for the IAM token config at the default path, which does not exist.
client = FilestoreCliClient(
self.__binary_path,
self.__port,
Expand All @@ -48,5 +50,7 @@ def get_client(self, auth_token):
config_path=str(self.__client_config_path),
check_exit_code=False,
return_json=True,
use_unix_socket=use_unix_socket,
verbose=True,
)
return client
13 changes: 13 additions & 0 deletions cloud/filestore/tests/auth/new/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ def test_new_auth_authorization_ok():
log_result("test_new_auth_authorization_ok", result)
assert result.returncode == 0

# TODO: enable when unix sockets without auth are supported
# def test_unix_socket_does_not_require_auth():
# fixture = TestFixture()
# client = fixture.get_client("some-token", use_unix_socket=True)
# result = client.create(
# "test_unix_socket_does_not_require_auth",
# "some_cloud",
# fixture.folder_id,
# return_stdout=False,
# )
# log_result("test_unix_socket_does_not_require_auth", result)
# assert result.returncode != 0


def test_new_auth_unauthorized():
fixture = TestFixture()
Expand Down
1 change: 1 addition & 0 deletions cloud/filestore/tests/auth/new/ya.make
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ PEERDIR(
cloud/filestore/tests/python/lib
)

SET(USE_UNIX_SOCKET 1)
INCLUDE(${ARCADIA_ROOT}/cloud/storage/core/tests/recipes/access-service-new.inc)
INCLUDE(${ARCADIA_ROOT}/cloud/filestore/tests/recipes/service-kikimr.inc)

Expand Down
7 changes: 7 additions & 0 deletions cloud/filestore/tests/python/lib/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def __init__(
auth_token=None,
check_exit_code=True,
return_json=False,
use_unix_socket=False,
):
self.__binary_path = binary_path
self.__port = port
Expand All @@ -41,6 +42,10 @@ def __init__(
self.__env = {}
self.__check_exit_code = check_exit_code
self.__return_json = return_json
if use_unix_socket:
self.__server_unix_socket_path = os.getenv("NFS_SERVER_UNIX_SOCKET_PATH")
else:
self.__server_unix_socket_path = None
if auth_token is not None:
self.__env = {"IAM_TOKEN": auth_token}

Expand Down Expand Up @@ -273,6 +278,8 @@ def __cmd_opts(self, vhost=False):
opts += ["--verbose", "trace"]
if self.__return_json:
opts += ["--json"]
if self.__server_unix_socket_path is not None:
opts += ["--server-unix-socket-path", self.__server_unix_socket_path]
return opts

def standard_command(input_arg):
Expand Down
4 changes: 4 additions & 0 deletions cloud/filestore/tests/recipes/service-kikimr.inc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ IF (NOT OPENSOURCE OR NFS_FORCE_VERBOSE)
SET_APPEND(RECIPE_ARGS --verbose)
ENDIF()

IF (USE_UNIX_SOCKET)
SET_APPEND(RECIPE_ARGS --use-unix-socket)
ENDIF()

USE_RECIPE(
cloud/filestore/tests/recipes/service-kikimr/service-kikimr-recipe
${RECIPE_ARGS}
Expand Down
9 changes: 9 additions & 0 deletions cloud/filestore/tests/recipes/service-kikimr/__main__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import argparse
import logging
import os
import pathlib
import tempfile

import yatest.common as common
import google.protobuf.text_format as text_format
Expand Down Expand Up @@ -35,6 +37,7 @@ def start(argv):
parser.add_argument("--restart-interval", action="store", default=None)
parser.add_argument("--storage-config-patch", action="store", default=None)
parser.add_argument("--bs-cache-file-path", action="store", default=None)
parser.add_argument("--use-unix-socket", action="store_true", default=False)
args = parser.parse_args(argv)

kikimr_binary_path = common.binary_path("cloud/storage/core/tools/testing/ydb/bin/ydbd")
Expand Down Expand Up @@ -73,6 +76,12 @@ def start(argv):
storage_config = text_format.Parse(
p.read(),
TStorageConfig())
if args.use_unix_socket:
# Create in temp directory because we would like a shorter path
server_unix_socket_path = str(
pathlib.Path(tempfile.mkdtemp(dir="/tmp")) / "filestore.sock")
set_env("NFS_SERVER_UNIX_SOCKET_PATH", server_unix_socket_path)
server_config.ServerConfig.UnixSocketPath = server_unix_socket_path

secure = False
if access_service_port:
Expand Down

0 comments on commit 0c825cc

Please sign in to comment.