Correct live/ready checks to consider special host values (#2182)
This commit is contained in:
+34
-15
@@ -1,3 +1,4 @@
|
|||||||
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
module PostgREST.Admin
|
module PostgREST.Admin
|
||||||
( postgrestAdmin
|
( postgrestAdmin
|
||||||
) where
|
) where
|
||||||
@@ -21,7 +22,7 @@ import Protolude
|
|||||||
-- | PostgREST admin application
|
-- | PostgREST admin application
|
||||||
postgrestAdmin :: AppState.AppState -> AppConfig -> Wai.Application
|
postgrestAdmin :: AppState.AppState -> AppConfig -> Wai.Application
|
||||||
postgrestAdmin appState appConfig req respond = do
|
postgrestAdmin appState appConfig req respond = do
|
||||||
isMainAppReachable <- isRight <$> reachMainApp appConfig
|
isMainAppReachable <- any isRight <$> reachMainApp appConfig
|
||||||
isSchemaCacheLoaded <- isJust <$> AppState.getDbStructure appState
|
isSchemaCacheLoaded <- isJust <$> AppState.getDbStructure appState
|
||||||
isConnectionUp <-
|
isConnectionUp <-
|
||||||
if configDbChannelEnabled appConfig
|
if configDbChannelEnabled appConfig
|
||||||
@@ -38,19 +39,37 @@ postgrestAdmin appState appConfig req respond = do
|
|||||||
|
|
||||||
-- Try to connect to the main app socket
|
-- Try to connect to the main app socket
|
||||||
-- Note that it doesn't even send a valid HTTP request, we just want to check that the main app is accepting connections
|
-- Note that it doesn't even send a valid HTTP request, we just want to check that the main app is accepting connections
|
||||||
reachMainApp :: AppConfig -> IO (Either IOException ())
|
-- The code for resolving the "*4", "!4", "*6", "!6", "*" special values is taken from
|
||||||
reachMainApp appConfig =
|
-- https://hackage.haskell.org/package/streaming-commons-0.2.2.4/docs/src/Data.Streaming.Network.html#bindPortGenEx
|
||||||
try . withSocketsDo $ bracket open close sendEmpty
|
reachMainApp :: AppConfig -> IO [Either IOException ()]
|
||||||
where
|
reachMainApp AppConfig{..} =
|
||||||
open = case configServerUnixSocket appConfig of
|
case configServerUnixSocket of
|
||||||
Just path -> do
|
Just path -> do
|
||||||
sock <- socket AF_UNIX Stream 0
|
sock <- socket AF_UNIX Stream 0
|
||||||
|
(:[]) <$> try (do
|
||||||
connect sock $ SockAddrUnix path
|
connect sock $ SockAddrUnix path
|
||||||
return sock
|
withSocketsDo $ bracket (pure sock) close sendEmpty)
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
let hints = defaultHints { addrSocketType = Stream }
|
let
|
||||||
addr:_ <- getAddrInfo (Just hints) (Just . T.unpack $ configServerHost appConfig) (Just . show $ configServerPort appConfig)
|
host | configServerHost `elem` ["*4", "!4", "*6", "!6", "*"] = Nothing
|
||||||
sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
|
| otherwise = Just configServerHost
|
||||||
connect sock $ addrAddress addr
|
filterAddrs xs =
|
||||||
return sock
|
case configServerHost of
|
||||||
|
"*4" -> ipv4Addrs xs ++ ipv6Addrs xs
|
||||||
|
"!4" -> ipv4Addrs xs
|
||||||
|
"*6" -> ipv6Addrs xs ++ ipv4Addrs xs
|
||||||
|
"!6" -> ipv6Addrs xs
|
||||||
|
_ -> xs
|
||||||
|
ipv4Addrs xs = filter ((/=) AF_INET6 . addrFamily) xs
|
||||||
|
ipv6Addrs xs = filter ((==) AF_INET6 . addrFamily) xs
|
||||||
|
|
||||||
|
addrs <- getAddrInfo (Just $ defaultHints { addrSocketType = Stream }) (T.unpack <$> host) (Just . show $ configServerPort)
|
||||||
|
tryAddr `traverse` filterAddrs addrs
|
||||||
|
where
|
||||||
sendEmpty sock = void $ send sock mempty
|
sendEmpty sock = void $ send sock mempty
|
||||||
|
tryAddr :: AddrInfo -> IO (Either IOException ())
|
||||||
|
tryAddr addr = do
|
||||||
|
sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
|
||||||
|
try $ do
|
||||||
|
connect sock $ addrAddress addr
|
||||||
|
withSocketsDo $ bracket (pure sock) close sendEmpty
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ run installHandlers maybeRunWithSocket appState = do
|
|||||||
AppState.logWithZTime appState $ "Listening on unix socket " <> show socket
|
AppState.logWithZTime appState $ "Listening on unix socket " <> show socket
|
||||||
runWithSocket (serverSettings conf) app configServerUnixSocketMode socket
|
runWithSocket (serverSettings conf) app configServerUnixSocketMode socket
|
||||||
Nothing ->
|
Nothing ->
|
||||||
panic "Cannot run with socket on non-unix plattforms."
|
panic "Cannot run with unix socket on non-unix plattforms."
|
||||||
Nothing ->
|
Nothing ->
|
||||||
do
|
do
|
||||||
AppState.logWithZTime appState $ "Listening on port " <> show configServerPort
|
AppState.logWithZTime appState $ "Listening on port " <> show configServerPort
|
||||||
|
|||||||
@@ -171,3 +171,10 @@ invalidjointypes:
|
|||||||
- 'left!'
|
- 'left!'
|
||||||
- 'right'
|
- 'right'
|
||||||
- '.#$$%&$%/'
|
- '.#$$%&$%/'
|
||||||
|
|
||||||
|
specialhostvalues:
|
||||||
|
- '*4'
|
||||||
|
- '!4'
|
||||||
|
- '*6'
|
||||||
|
- '!6'
|
||||||
|
- '*'
|
||||||
|
|||||||
+13
-2
@@ -140,7 +140,7 @@ def dumpconfig(configpath=None, env=None, stdin=None):
|
|||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def run(configpath=None, stdin=None, env=None, port=None):
|
def run(configpath=None, stdin=None, env=None, port=None, host=None):
|
||||||
"Run PostgREST and yield an endpoint that is ready for connections."
|
"Run PostgREST and yield an endpoint that is ready for connections."
|
||||||
env = env or {}
|
env = env or {}
|
||||||
env["PGRST_DB_POOL"] = "1"
|
env["PGRST_DB_POOL"] = "1"
|
||||||
@@ -149,7 +149,7 @@ def run(configpath=None, stdin=None, env=None, port=None):
|
|||||||
with tempfile.TemporaryDirectory() as tmpdir:
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
if port:
|
if port:
|
||||||
env["PGRST_SERVER_PORT"] = str(port)
|
env["PGRST_SERVER_PORT"] = str(port)
|
||||||
env["PGRST_SERVER_HOST"] = "localhost"
|
env["PGRST_SERVER_HOST"] = host or "localhost"
|
||||||
baseurl = f"http://localhost:{port}"
|
baseurl = f"http://localhost:{port}"
|
||||||
else:
|
else:
|
||||||
socketfile = pathlib.Path(tmpdir) / "postgrest.sock"
|
socketfile = pathlib.Path(tmpdir) / "postgrest.sock"
|
||||||
@@ -883,6 +883,17 @@ def test_admin_live_dependent_on_main_app(defaultenv):
|
|||||||
response = postgrest.admin.get("/live")
|
response = postgrest.admin.get("/live")
|
||||||
assert response.status_code == 503
|
assert response.status_code == 503
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("specialhostvalue", FIXTURES["specialhostvalues"])
|
||||||
|
def test_admin_works_with_host_special_values(specialhostvalue, defaultenv):
|
||||||
|
"Should get a success from the admin live and ready endpoints when using special host values for the main app"
|
||||||
|
|
||||||
|
with run(env=defaultenv, port=freeport(), host=specialhostvalue) as postgrest:
|
||||||
|
|
||||||
|
response = postgrest.admin.get("/live")
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
response = postgrest.admin.get("/ready")
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"level, has_output",
|
"level, has_output",
|
||||||
|
|||||||
Reference in New Issue
Block a user