Add server-unix-socket config option (#1303)

Add ncat workaround to test socket connection on CircleCI
This commit is contained in:
Dan Amoroso
2019-06-05 12:57:47 -05:00
committed by Steve Chávez
parent e292fb5eb9
commit 78e5677fbe
8 changed files with 102 additions and 18 deletions
+5
View File
@@ -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: |
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
+6
View File
@@ -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 = ""
| |
+2
View File
@@ -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
+27
View File
@@ -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
+7
View File
@@ -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"