Add server-unix-socket config option (#1303)
Add ncat workaround to test socket connection on CircleCI
This commit is contained in:
committed by
Steve Chávez
parent
e292fb5eb9
commit
78e5677fbe
@@ -66,6 +66,11 @@ jobs:
|
|||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- v1-stack-dependencies-{{ checksum "postgrest.cabal" }}-{{ checksum "stack.yaml" }}
|
- v1-stack-dependencies-{{ checksum "postgrest.cabal" }}-{{ checksum "stack.yaml" }}
|
||||||
|
- run:
|
||||||
|
name: install ncat
|
||||||
|
command: |
|
||||||
|
# utility needed to test socket connection with curl < 7.40
|
||||||
|
sudo apt-get install nmap
|
||||||
- run:
|
- run:
|
||||||
name: install stack & dependencies
|
name: install stack & dependencies
|
||||||
command: |
|
command: |
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- #1186, Add support for user defined unix socket via `server-unix-socket` config option
|
||||||
- #690, Add `?columns` query parameter for faster bulk inserts, also ignores unspecified json keys in a payload - @steve-chavez
|
- #690, Add `?columns` query parameter for faster bulk inserts, also ignores unspecified json keys in a payload - @steve-chavez
|
||||||
- #1239, Add support for resource embedding on materialized views - @vitorbaptista
|
- #1239, Add support for resource embedding on materialized views - @vitorbaptista
|
||||||
- #1264, Add support for bulk RPC call - @steve-chavez
|
- #1264, Add support for bulk RPC call - @steve-chavez
|
||||||
|
|||||||
+49
-16
@@ -15,13 +15,22 @@ import Control.Retry (RetryStatus, capDelay,
|
|||||||
import Data.IORef (IORef, atomicWriteIORef, newIORef,
|
import Data.IORef (IORef, atomicWriteIORef, newIORef,
|
||||||
readIORef)
|
readIORef)
|
||||||
import Data.String (IsString (..))
|
import Data.String (IsString (..))
|
||||||
import Data.Text (pack, replace, strip, stripPrefix)
|
import Data.Text (pack, replace, strip, stripPrefix,
|
||||||
|
unpack)
|
||||||
import Data.Text.Encoding (decodeUtf8, encodeUtf8)
|
import Data.Text.Encoding (decodeUtf8, encodeUtf8)
|
||||||
import Data.Text.IO (hPutStrLn, readFile)
|
import Data.Text.IO (hPutStrLn, readFile)
|
||||||
import Data.Time.Clock (getCurrentTime)
|
import Data.Time.Clock (getCurrentTime)
|
||||||
|
import Network.Socket (Family (AF_UNIX),
|
||||||
|
SockAddr (SockAddrUnix), Socket,
|
||||||
|
SocketType (Stream), bind, close,
|
||||||
|
defaultProtocol, listen,
|
||||||
|
maxListenQueue, socket)
|
||||||
import Network.Wai.Handler.Warp (defaultSettings, runSettings,
|
import Network.Wai.Handler.Warp (defaultSettings, runSettings,
|
||||||
setHost, setPort, setServerName)
|
runSettingsSocket, setHost, setPort,
|
||||||
|
setServerName)
|
||||||
|
import System.Directory (removeFile)
|
||||||
import System.IO (BufferMode (..), hSetBuffering)
|
import System.IO (BufferMode (..), hSetBuffering)
|
||||||
|
import System.IO.Error (isDoesNotExistError)
|
||||||
|
|
||||||
import PostgREST.App (postgrest)
|
import PostgREST.App (postgrest)
|
||||||
import PostgREST.Config (AppConfig (..), configPoolTimeout',
|
import PostgREST.Config (AppConfig (..), configPoolTimeout',
|
||||||
@@ -153,6 +162,7 @@ main = do
|
|||||||
let host = configHost conf
|
let host = configHost conf
|
||||||
port = configPort conf
|
port = configPort conf
|
||||||
proxy = configProxyUri conf
|
proxy = configProxyUri conf
|
||||||
|
maybeSocketAddr = configSocket conf
|
||||||
pgSettings = toS (configDatabase conf) -- is the db-uri
|
pgSettings = toS (configDatabase conf) -- is the db-uri
|
||||||
roleClaimKey = configRoleClaimKey conf
|
roleClaimKey = configRoleClaimKey conf
|
||||||
appSettings =
|
appSettings =
|
||||||
@@ -170,7 +180,6 @@ main = do
|
|||||||
when (isLeft roleClaimKey) $
|
when (isLeft roleClaimKey) $
|
||||||
panic $ show roleClaimKey
|
panic $ show roleClaimKey
|
||||||
|
|
||||||
putStrLn $ ("Listening on port " :: Text) <> show (configPort conf)
|
|
||||||
--
|
--
|
||||||
-- create connection pool with the provided settings, returns either
|
-- create connection pool with the provided settings, returns either
|
||||||
-- a 'Connection' or a 'ConnectionError'. Does not throw.
|
-- a 'Connection' or a 'ConnectionError'. Does not throw.
|
||||||
@@ -222,19 +231,31 @@ main = do
|
|||||||
-- ask for the OS time at most once per second
|
-- ask for the OS time at most once per second
|
||||||
getTime <- mkAutoUpdate defaultUpdateSettings {updateAction = getCurrentTime}
|
getTime <- mkAutoUpdate defaultUpdateSettings {updateAction = getCurrentTime}
|
||||||
|
|
||||||
-- run the postgrest application
|
let postgrestApplication =
|
||||||
runSettings appSettings $
|
postgrest
|
||||||
postgrest
|
conf
|
||||||
conf
|
refDbStructure
|
||||||
refDbStructure
|
pool
|
||||||
pool
|
getTime
|
||||||
getTime
|
(connectionWorker
|
||||||
(connectionWorker
|
mainTid
|
||||||
mainTid
|
pool
|
||||||
pool
|
(configSchema conf)
|
||||||
(configSchema conf)
|
refDbStructure
|
||||||
refDbStructure
|
refIsWorkerOn)
|
||||||
refIsWorkerOn)
|
in case maybeSocketAddr of
|
||||||
|
Nothing -> do
|
||||||
|
-- run the postgrest application
|
||||||
|
putStrLn $ ("Listening on port " :: Text) <> show (configPort conf)
|
||||||
|
runSettings appSettings postgrestApplication
|
||||||
|
Just socketAddr -> do
|
||||||
|
-- run postgrest application with user defined socket
|
||||||
|
sock <- createAndBindSocket (unpack socketAddr)
|
||||||
|
listen sock maxListenQueue
|
||||||
|
putStrLn $ ("Listening on unix socket " :: Text) <> show socketAddr
|
||||||
|
runSettingsSocket appSettings sock postgrestApplication
|
||||||
|
-- clean socket up when done
|
||||||
|
close sock
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
The purpose of this function is to load the JWT secret from a file if
|
The purpose of this function is to load the JWT secret from a file if
|
||||||
@@ -302,3 +323,15 @@ loadDbUriFile conf = extractDbUri mDbUri
|
|||||||
Nothing -> return dbUri
|
Nothing -> return dbUri
|
||||||
Just filename -> strip <$> readFile (toS filename)
|
Just filename -> strip <$> readFile (toS filename)
|
||||||
setDbUri dbUri = conf {configDatabase = dbUri}
|
setDbUri dbUri = conf {configDatabase = dbUri}
|
||||||
|
|
||||||
|
createAndBindSocket :: FilePath -> IO Socket
|
||||||
|
createAndBindSocket filePath = do
|
||||||
|
deleteSocketFileIfExist filePath
|
||||||
|
sock <- socket AF_UNIX Stream defaultProtocol
|
||||||
|
bind sock $ SockAddrUnix filePath
|
||||||
|
return sock
|
||||||
|
where
|
||||||
|
deleteSocketFileIfExist path = removeFile path `catch` handleDoesNotExist
|
||||||
|
handleDoesNotExist e
|
||||||
|
| isDoesNotExistError e = return ()
|
||||||
|
| otherwise = throwIO e
|
||||||
|
|||||||
+5
-2
@@ -33,17 +33,20 @@ executable postgrest
|
|||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
build-depends: auto-update
|
build-depends: auto-update
|
||||||
, base >= 4.8 && < 4.10
|
, base >= 4.8 && < 4.10
|
||||||
, base64-bytestring
|
|
||||||
, bytestring
|
|
||||||
, hasql >= 1.3 && < 1.4
|
, hasql >= 1.3 && < 1.4
|
||||||
, hasql-pool >= 0.5 && < 0.6
|
, hasql-pool >= 0.5 && < 0.6
|
||||||
, hasql-transaction >= 0.7 && < 0.8
|
, hasql-transaction >= 0.7 && < 0.8
|
||||||
|
, network == 2.6.3.2
|
||||||
, postgrest
|
, postgrest
|
||||||
, protolude == 0.2.2
|
, protolude == 0.2.2
|
||||||
, retry
|
, retry
|
||||||
, text
|
, text
|
||||||
, time
|
, time
|
||||||
, warp
|
, warp
|
||||||
|
, bytestring
|
||||||
|
, base64-bytestring
|
||||||
|
, retry
|
||||||
|
, directory
|
||||||
if !os(windows)
|
if !os(windows)
|
||||||
build-depends: unix
|
build-depends: unix
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ data AppConfig = AppConfig {
|
|||||||
, configSchema :: Text
|
, configSchema :: Text
|
||||||
, configHost :: Text
|
, configHost :: Text
|
||||||
, configPort :: Int
|
, configPort :: Int
|
||||||
|
, configSocket :: Maybe Text
|
||||||
|
|
||||||
, configJwtSecret :: Maybe B.ByteString
|
, configJwtSecret :: Maybe B.ByteString
|
||||||
, configJwtSecretIsBase64 :: Bool
|
, configJwtSecretIsBase64 :: Bool
|
||||||
@@ -149,6 +150,7 @@ readOptions = do
|
|||||||
<*> reqString "db-schema"
|
<*> reqString "db-schema"
|
||||||
<*> (fromMaybe "!4" . mfilter (/= "") <$> optString "server-host")
|
<*> (fromMaybe "!4" . mfilter (/= "") <$> optString "server-host")
|
||||||
<*> (fromMaybe 3000 . join . fmap coerceInt <$> optValue "server-port")
|
<*> (fromMaybe 3000 . join . fmap coerceInt <$> optValue "server-port")
|
||||||
|
<*> optString "server-unix-socket"
|
||||||
<*> (fmap encodeUtf8 . mfilter (/= "") <$> optString "jwt-secret")
|
<*> (fmap encodeUtf8 . mfilter (/= "") <$> optString "jwt-secret")
|
||||||
<*> (fromMaybe False . join . fmap coerceBool <$> optValue "secret-is-base64")
|
<*> (fromMaybe False . join . fmap coerceBool <$> optValue "secret-is-base64")
|
||||||
<*> parseJwtAudience "jwt-aud"
|
<*> parseJwtAudience "jwt-aud"
|
||||||
@@ -231,6 +233,10 @@ readOptions = do
|
|||||||
|server-host = "!4"
|
|server-host = "!4"
|
||||||
|server-port = 3000
|
|server-port = 3000
|
||||||
|
|
|
|
||||||
|
|## unix socket location
|
||||||
|
|## if specified it takes precedence over server-port
|
||||||
|
|# server-unix-socket = "/tmp/pgrst.sock"
|
||||||
|
|
|
||||||
|## base url for swagger output
|
|## base url for swagger output
|
||||||
|# server-proxy-uri = ""
|
|# server-proxy-uri = ""
|
||||||
|
|
|
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ getEnvVarWithDefault var def = toS <$>
|
|||||||
_baseCfg :: AppConfig
|
_baseCfg :: AppConfig
|
||||||
_baseCfg = -- Connection Settings
|
_baseCfg = -- Connection Settings
|
||||||
AppConfig mempty "postgrest_test_anonymous" Nothing "test" "localhost" 3000
|
AppConfig mempty "postgrest_test_anonymous" Nothing "test" "localhost" 3000
|
||||||
|
-- No user configured Unix Socket
|
||||||
|
Nothing
|
||||||
-- Jwt settings
|
-- Jwt settings
|
||||||
(Just $ encodeUtf8 "reallyreallyreallyreallyverysafe") False Nothing
|
(Just $ encodeUtf8 "reallyreallyreallyreallyverysafe") False Nothing
|
||||||
-- Connection Modifiers
|
-- Connection Modifiers
|
||||||
|
|||||||
@@ -181,6 +181,30 @@ ensureAppSettings(){
|
|||||||
pgrStop
|
pgrStop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSocketStatus() {
|
||||||
|
curl -sL -w "%{http_code}\\n" -o /dev/null localhost:54321
|
||||||
|
}
|
||||||
|
|
||||||
|
socketConnection(){
|
||||||
|
# map port 54321 traffic to unix socket as workaround for curl below 7.40
|
||||||
|
# not supporting --unix-socket flag
|
||||||
|
ncat -vlk 54321 -c 'ncat -U /tmp/postgrest.sock' &
|
||||||
|
pgrStart "./configs/unix-socket.config"
|
||||||
|
while pgrStarted && test "$( getSocketStatus )" -ne 200
|
||||||
|
do
|
||||||
|
# wait for the server to start
|
||||||
|
sleep 0.1 \
|
||||||
|
|| sleep 1 # fallback: subsecond sleep is not standard and may fail
|
||||||
|
done
|
||||||
|
if test $( getSocketStatus ) -eq 200
|
||||||
|
then
|
||||||
|
ok "Succesfully connected through unix socket"
|
||||||
|
else
|
||||||
|
ko "Failed to connect through unix socket"
|
||||||
|
fi
|
||||||
|
pgrStop
|
||||||
|
}
|
||||||
|
|
||||||
# PRE: curl must be available
|
# PRE: curl must be available
|
||||||
test -n "$(command -v curl)" || bailOut 'curl is not available'
|
test -n "$(command -v curl)" || bailOut 'curl is not available'
|
||||||
|
|
||||||
@@ -191,6 +215,8 @@ setUp
|
|||||||
|
|
||||||
echo "Running IO tests.."
|
echo "Running IO tests.."
|
||||||
|
|
||||||
|
socketConnection
|
||||||
|
|
||||||
readSecretFromFile word.noeol 'simple (no EOL)'
|
readSecretFromFile word.noeol 'simple (no EOL)'
|
||||||
readSecretFromFile word.txt 'simple'
|
readSecretFromFile word.txt 'simple'
|
||||||
readSecretFromFile ascii.noeol 'ASCII (no EOL)'
|
readSecretFromFile ascii.noeol 'ASCII (no EOL)'
|
||||||
@@ -224,6 +250,7 @@ invalidRoleClaimKey 1234
|
|||||||
ensureIatClaimWorks
|
ensureIatClaimWorks
|
||||||
ensureAppSettings
|
ensureAppSettings
|
||||||
|
|
||||||
|
|
||||||
cleanUp
|
cleanUp
|
||||||
|
|
||||||
exit $failedTests
|
exit $failedTests
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
db-uri = "postgres:///postgrest_test"
|
||||||
|
db-schema = "test"
|
||||||
|
db-anon-role = "postgrest_test_anonymous"
|
||||||
|
db-pool = 1
|
||||||
|
server-host = "127.0.0.1"
|
||||||
|
server-unix-socket = "/tmp/postgrest.sock"
|
||||||
|
jwt-secret = "reallyreallyreallyreallyverysafe"
|
||||||
Reference in New Issue
Block a user