mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
--uds option for binding to Unix domain socket, closes #1388
This commit is contained in:
parent
e0064ba7b0
commit
180c7a5328
6 changed files with 65 additions and 2 deletions
|
|
@ -333,6 +333,10 @@ def uninstall(packages, yes):
|
||||||
type=click.IntRange(0, 65535),
|
type=click.IntRange(0, 65535),
|
||||||
help="Port for server, defaults to 8001. Use -p 0 to automatically assign an available port.",
|
help="Port for server, defaults to 8001. Use -p 0 to automatically assign an available port.",
|
||||||
)
|
)
|
||||||
|
@click.option(
|
||||||
|
"--uds",
|
||||||
|
help="Bind to a Unix domain socket",
|
||||||
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--reload",
|
"--reload",
|
||||||
is_flag=True,
|
is_flag=True,
|
||||||
|
|
@ -428,6 +432,7 @@ def serve(
|
||||||
immutable,
|
immutable,
|
||||||
host,
|
host,
|
||||||
port,
|
port,
|
||||||
|
uds,
|
||||||
reload,
|
reload,
|
||||||
cors,
|
cors,
|
||||||
sqlite_extensions,
|
sqlite_extensions,
|
||||||
|
|
@ -569,6 +574,8 @@ def serve(
|
||||||
uvicorn_kwargs = dict(
|
uvicorn_kwargs = dict(
|
||||||
host=host, port=port, log_level="info", lifespan="on", workers=1
|
host=host, port=port, log_level="info", lifespan="on", workers=1
|
||||||
)
|
)
|
||||||
|
if uds:
|
||||||
|
uvicorn_kwargs["uds"] = uds
|
||||||
if ssl_keyfile:
|
if ssl_keyfile:
|
||||||
uvicorn_kwargs["ssl_keyfile"] = ssl_keyfile
|
uvicorn_kwargs["ssl_keyfile"] = ssl_keyfile
|
||||||
if ssl_certfile:
|
if ssl_certfile:
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ Options:
|
||||||
machines.
|
machines.
|
||||||
-p, --port INTEGER RANGE Port for server, defaults to 8001. Use -p 0 to automatically
|
-p, --port INTEGER RANGE Port for server, defaults to 8001. Use -p 0 to automatically
|
||||||
assign an available port. [0<=x<=65535]
|
assign an available port. [0<=x<=65535]
|
||||||
|
--uds TEXT Bind to a Unix domain socket
|
||||||
--reload Automatically reload if code or metadata change detected -
|
--reload Automatically reload if code or metadata change detected -
|
||||||
useful for development
|
useful for development
|
||||||
--cors Enable CORS by serving Access-Control-Allow-Origin: *
|
--cors Enable CORS by serving Access-Control-Allow-Origin: *
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,6 @@ Here is an example of an `nginx <https://nginx.org/>`__ configuration file that
|
||||||
http {
|
http {
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
|
|
||||||
location /my-datasette {
|
location /my-datasette {
|
||||||
proxy_pass http://127.0.0.1:8009/my-datasette;
|
proxy_pass http://127.0.0.1:8009/my-datasette;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
|
@ -157,6 +156,28 @@ Here is an example of an `nginx <https://nginx.org/>`__ configuration file that
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
You can also use the ``--uds`` option to Datasette to listen on a Unix domain socket instead of a port, configuring the nginx upstream proxy like this::
|
||||||
|
|
||||||
|
daemon off;
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
http {
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
location / {
|
||||||
|
proxy_pass http://datasette;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
upstream datasette {
|
||||||
|
server unix:/tmp/datasette.sock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Then run Datasette with ``datasette --uds /tmp/datasette.sock path/to/database.db``.
|
||||||
|
|
||||||
Apache proxy configuration
|
Apache proxy configuration
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,6 @@ def ds_localhost_https_server(tmp_path_factory):
|
||||||
for blob in server_cert.cert_chain_pems:
|
for blob in server_cert.cert_chain_pems:
|
||||||
blob.write_to_path(path=certfile, append=True)
|
blob.write_to_path(path=certfile, append=True)
|
||||||
ca.cert_pem.write_to_path(path=client_cert)
|
ca.cert_pem.write_to_path(path=client_cert)
|
||||||
|
|
||||||
ds_proc = subprocess.Popen(
|
ds_proc = subprocess.Popen(
|
||||||
[
|
[
|
||||||
"datasette",
|
"datasette",
|
||||||
|
|
@ -154,3 +153,22 @@ def ds_localhost_https_server(tmp_path_factory):
|
||||||
yield ds_proc, client_cert
|
yield ds_proc, client_cert
|
||||||
# Shut it down at the end of the pytest session
|
# Shut it down at the end of the pytest session
|
||||||
ds_proc.terminate()
|
ds_proc.terminate()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def ds_unix_domain_socket_server(tmp_path_factory):
|
||||||
|
socket_folder = tmp_path_factory.mktemp("uds")
|
||||||
|
uds = str(socket_folder / "datasette.sock")
|
||||||
|
ds_proc = subprocess.Popen(
|
||||||
|
["datasette", "--memory", "--uds", uds],
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
cwd=tempfile.gettempdir(),
|
||||||
|
)
|
||||||
|
# Give the server time to start
|
||||||
|
time.sleep(1.5)
|
||||||
|
# Check it started successfully
|
||||||
|
assert not ds_proc.poll(), ds_proc.stdout.read().decode("utf-8")
|
||||||
|
yield ds_proc, uds
|
||||||
|
# Shut it down at the end of the pytest session
|
||||||
|
ds_proc.terminate()
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,7 @@ def test_metadata_yaml():
|
||||||
immutable=[],
|
immutable=[],
|
||||||
host="127.0.0.1",
|
host="127.0.0.1",
|
||||||
port=8001,
|
port=8001,
|
||||||
|
uds=None,
|
||||||
reload=False,
|
reload=False,
|
||||||
cors=False,
|
cors=False,
|
||||||
sqlite_extensions=[],
|
sqlite_extensions=[],
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import httpx
|
import httpx
|
||||||
import pytest
|
import pytest
|
||||||
|
import socket
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.serial
|
@pytest.mark.serial
|
||||||
|
|
@ -21,3 +22,17 @@ def test_serve_localhost_https(ds_localhost_https_server):
|
||||||
"path": "/_memory",
|
"path": "/_memory",
|
||||||
"tables": [],
|
"tables": [],
|
||||||
}.items() <= response.json().items()
|
}.items() <= response.json().items()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.serial
|
||||||
|
@pytest.mark.skipif(not hasattr(socket, "AF_UNIX"), reason="Requires socket.AF_UNIX support")
|
||||||
|
def test_serve_unix_domain_socket(ds_unix_domain_socket_server):
|
||||||
|
_, uds = ds_unix_domain_socket_server
|
||||||
|
transport = httpx.HTTPTransport(uds=uds)
|
||||||
|
client = httpx.Client(transport=transport)
|
||||||
|
response = client.get("http://localhost/_memory.json")
|
||||||
|
assert {
|
||||||
|
"database": "_memory",
|
||||||
|
"path": "/_memory",
|
||||||
|
"tables": [],
|
||||||
|
}.items() <= response.json().items()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue