Skip to content

Commit

Permalink
[tools] added fake-vhost-server
Browse files Browse the repository at this point in the history
  • Loading branch information
sharpeye committed Jan 30, 2024
1 parent 9c51f27 commit 5097d0f
Show file tree
Hide file tree
Showing 4 changed files with 255 additions and 0 deletions.
242 changes: 242 additions & 0 deletions cloud/blockstore/tools/testing/fake-vhost-server/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
import argparse
import json
import logging
import signal
import sys

from datetime import datetime
from http.server import HTTPServer, BaseHTTPRequestHandler
from threading import Thread


def _prepare_logging(verbose):
log_level = {
"error": logging.ERROR,
"warn": logging.WARNING,
"info": logging.INFO,
"debug": logging.DEBUG,
}[verbose]

logging.basicConfig(
stream=sys.stderr,
level=log_level,
format="[%(levelname)s] [%(asctime)s] %(message)s")


class _DeviceChunk:

def __init__(self, s: str):
i = s.rfind(':')
if i == -1 or i == 0:
raise argparse.ArgumentTypeError(f"invalid format: {s}")

j = s[0:i-1].rfind(':')
if j == -1:
raise argparse.ArgumentTypeError(f"invalid format: {s}")

self.offset = int(s[i+1:])
self.size = int(s[j+1:i])
self.path = s[:j]

def __str__(self):
return f"[{self.path} {self.size} {self.offset}]"


class _App:

def __init__(self):
self.exit_code = 0

def terminate(self, exit_code):
self.exit_code = exit_code
exit(exit_code)


def _create_handler(args, app: _App):

class Handler(BaseHTTPRequestHandler):

def do_GET(self):
self.log_request()

if self.path == '/ping':
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write('pong'.encode('utf-8'))
return

self.send_error(400)

def do_POST(self):
self.log_request()

length = int(self.headers['content-length'])
req = self.rfile.read(length).decode('utf-8')

if self.path != '/crash':
self.send_error(400)
return

data = json.loads(req)

exit_code = data.get('exit_code', -1)
logging.info(f'exit with {exit_code}...')
app.terminate(exit_code)

return Handler


def _run_server(args):
app = _App()

server = HTTPServer(('localhost', args.port), _create_handler(args, app))

t0 = datetime.now()

def signal_handler(signum, frame):
if signum == signal.SIGUSR1:
# TODO
print(json.dumps({
"elapsed_ms": int((datetime.now() - t0).total_seconds() * 1000)
}))
return

logging.info('shutdown...')
server.shutdown()

signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGUSR1, signal_handler)

thread = Thread(target=server.serve_forever, name='server')

logging.info('start...')

thread.start()
thread.join()

logging.info('done')

return app.exit_code


def main():
parser = argparse.ArgumentParser()

# custom options

parser.add_argument('--port', type=int, required=True)

# vhost-server options

parser.add_argument(
"-v",
'--verbose',
help="output level for diagnostics messages",
default="debug",
type=str)

parser.add_argument("-s", '--socket-path', type=str, metavar="FILE", required=True)

parser.add_argument(
"-i",
"--serial",
type=str,
metavar="STR",
help="disk serial",
required=True)

parser.add_argument("--disk-id", type=str, metavar="STR", help="disk id")

parser.add_argument(
"--client-id",
type=str,
metavar="STR",
help="client id",
default="vhost-server")

parser.add_argument(
"--device",
required=True,
type=_DeviceChunk,
metavar="STR",
action="append",
help="specify device string path:size:offset "
"(e.g. /dev/vda:1000000:0, rdma://host:10020/abcdef:1000000:0)")

parser.add_argument(
"--device-backend",
type=str,
metavar="STR",
help="specify device backend",
choices=["aio", "rdma", "null"],
default="aio")

parser.add_argument(
"-r",
"--read-only",
action='store_true',
help="read only mode")

parser.add_argument(
"--no-sync",
action='store_true',
help="do not use O_SYNC")

parser.add_argument(
"--no-chmod",
action='store_true',
help="do not chmod socket")

parser.add_argument(
"-B",
"--batch-size",
type=int,
metavar="INT",
default=1024)

parser.add_argument(
"--block-size",
help="size of block device",
type=int,
metavar="INT",
default=512)

parser.add_argument(
"-q",
"--queue-count",
type=int,
metavar="INT",
default=0)

parser.add_argument(
"--log-type",
type=str,
metavar="STR",
choices=["json", "console"],
default="json")

parser.add_argument(
"--rdma-queue-size",
help="Rdma client queue size",
type=int,
metavar="INT",
default=256)

parser.add_argument(
"--rdma-max-buffer-size",
help="Rdma client queue size",
type=int,
metavar="INT",
default=4*1024**2 + 4096)

args = parser.parse_args()

_prepare_logging(args.verbose)

return _run_server(args)


if __name__ == '__main__':
exit(main())
11 changes: 11 additions & 0 deletions cloud/blockstore/tools/testing/fake-vhost-server/ya.make
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
PY3_PROGRAM()

PEERDIR(
# contrib/python/requests/py3
)

PY_SRCS(
__main__.py
)

END()
1 change: 1 addition & 0 deletions cloud/blockstore/tools/testing/ya.make
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ RECURSE(
eternal_tests
fake-conductor
fake-nbs
fake-vhost-server
generate-agents
infra-client
loadtest
Expand Down

0 comments on commit 5097d0f

Please sign in to comment.