这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,16 @@ For ``serve`` subcommand these are the flags available
access-key only mode or "Authorization" header is absent
in JWT mode

-s, --stripes Number of stripes
-s, --stripes Number of stripes (default: 1)

-c, --connections Number of connections that need to be opened to Postgres
(default: 50)

--timeout Each connection's idle time before it is closed
(default: 180 sec)

-i, --tx-iso Transaction isolation. read-commited / repeatable-read /
serializable

--root-dir This static dir is served at / and takes precedence over
all routes

--enable-console Enable API console. It is served at '/' and '/console'

Expand Down Expand Up @@ -103,6 +102,18 @@ These are the environment variables which are available:
<port>/<db-name> Example:
postgres://admin:mypass@mydomain.com:5432/mydb

HASURA_GRAPHQL_PG_STRIPES Number of stripes (default: 1)

HASURA_GRAPHQL_PG_CONNECTIONS Number of connections that need to be opened to
Postgres (default: 50)

HASURA_GRAPHQL_PG_TIMEOUT Each connection's idle time before it is closed
(default: 180 sec)

HASURA_GRAPHQL_TX_ISOLATION transaction isolation. read-committed /
repeatable-read / serializable
(default: read-commited)

HASURA_GRAPHQL_SERVER_PORT Port on which graphql-engine should be served

HASURA_GRAPHQL_ACCESS_KEY Secret access key, required to access this
Expand Down
3 changes: 3 additions & 0 deletions server/graphql-engine.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ library
-- regex related
, regex-tdfa >= 1.2

-- pretty printer
, ansi-wl-pprint

exposed-modules: Hasura.Server.App
, Hasura.Server.Auth
, Hasura.Server.Auth.JWT
Expand Down
158 changes: 62 additions & 96 deletions server/src-exec/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import Ops
import Control.Monad.STM (atomically)
import Data.Time.Clock (getCurrentTime)
import Options.Applicative
import System.Environment (lookupEnv)
import System.Exit (exitFailure)
import System.Environment (getEnvironment, lookupEnv)
import System.Exit (exitFailure, exitSuccess)

import qualified Control.Concurrent as C
import qualified Data.Aeson as A
Expand All @@ -23,13 +23,14 @@ import Hasura.Events.Lib
import Hasura.Logging (defaultLoggerSettings, mkLoggerCtx)
import Hasura.Prelude
import Hasura.RQL.DDL.Metadata (fetchMetadata)
import Hasura.RQL.Types (RoleName (..), adminUserInfo, QErr,
import Hasura.RQL.Types (QErr, RoleName (..), adminUserInfo,
emptySchemaCache)
import Hasura.Server.App (mkWaiApp)
import Hasura.Server.Auth
import Hasura.Server.CheckUpdates (checkForUpdates)
import Hasura.Server.Init
import Hasura.Server.Query (peelRun)
import Hasura.Server.Version (currentVersion)

import qualified Database.PG.Query as Q
import qualified Network.HTTP.Client.TLS as TLS
Expand All @@ -43,15 +44,15 @@ data RavenOptions

data ServeOptions
= ServeOptions
{ soPort :: !(Maybe Int)
{ soPort :: !Int
, soConnParams :: !Q.ConnParams
, soTxIso :: !Q.TxIsolation
, soRootDir :: !(Maybe String)
, soAccessKey :: !(Maybe AccessKey)
, soAuthHook :: !AuthHookConf
, soAuthHook :: !(Maybe AuthHook)
, soJwtSecret :: !(Maybe Text)
, soUnAuthRole :: !(Maybe RoleName)
, soCorsConfig :: !CorsConfigFlags
, soCorsConfig :: !CorsConfig
, soEnableConsole :: !Bool
} deriving (Show, Eq)

Expand All @@ -60,109 +61,94 @@ data RavenMode
| ROExport
| ROClean
| ROExecute
| ROVersion
deriving (Show, Eq)

parseRavenMode :: Parser RavenMode
parseRavenMode = subparser
( command "serve" (info (helper <*> serveOptsParser)
( progDesc "Start the HTTP api server" ))
<> command "export" (info (pure ROExport)
( progDesc "Export graphql-engine's schema to stdout" ))
<> command "clean" (info (pure ROClean)
( progDesc "Clean graphql-engine's metadata to start afresh" ))
<> command "execute" (info (pure ROExecute)
( progDesc "Execute a query" ))
)
parseRavenMode :: Env -> Parser (Either String RavenMode)
parseRavenMode env =
subparser
( command "serve" (info (helper <*> serveOptsParser)
( progDesc "Start the GraphQL Engine Server"
<> footerDoc (Just serveCmdFooter)
))
<> command "export" (info (pure $ Right ROExport)
( progDesc "Export graphql-engine's metadata to stdout" ))
<> command "clean" (info (pure $ Right ROClean)
( progDesc "Clean graphql-engine's metadata to start afresh" ))
<> command "execute" (info (pure $ Right ROExecute)
( progDesc "Execute a query" ))
<> command "version" (info (pure $ Right ROVersion)
(progDesc "Prints the version of GraphQL Engine"))
)
where
serveOptsParser = ROServe <$> serveOpts
serveOptsParser = runConfig env serveOptsconfig
serveOptsconfig = ROServe <$> serveOpts
serveOpts = ServeOptions
<$> parseServerPort
<*> parseConnParams
<*> parseTxIsolation
<*> parseRootDir
<*> parseAccessKey
<*> parseWebHook
<*> parseJwtSecret
<*> parseUnAuthRole
<*> parseCorsConfig
<*> parseEnableConsole

parseArgs :: IO RavenOptions
parseArgs = execParser opts
<$> configServerPort
<*> configConnParams
<*> configTxIsolation
<*> configRootDir
<*> configAccessKey
<*> configWebHook
<*> configJwtSecret
<*> configUnAuthRole
<*> configCorsConfig
<*> configEnableConsole

parseArgs :: Env -> IO RavenOptions
parseArgs env = do
eArgs <- execParser opts
either ((>> exitFailure) . putStrLn) return eArgs
where
optParser = RavenOptions <$> parseRawConnInfo <*> parseRavenMode
mkEitherRavenOpts a b = RavenOptions <$> a <*> b
optParser = liftA2 mkEitherRavenOpts parseRawConnInfo $ parseRavenMode env
parseRawConnInfo = runConfig env configRawConnInfo
opts = info (helper <*> optParser)
( fullDesc <>
header "Hasura's graphql-engine - Exposes Postgres over GraphQL")
header "Hasura GraphQL Engine: Realtime GraphQL API over Postgres with access control" <>
footerDoc (Just mainCmdFooter)
)

printJSON :: (A.ToJSON a) => a -> IO ()
printJSON = BLC.putStrLn . A.encode

printYaml :: (A.ToJSON a) => a -> IO ()
printYaml = BC.putStrLn . Y.encode

parseEnvAsBool :: String -> IO Bool
parseEnvAsBool envVar = do
mVal <- fmap T.pack <$> lookupEnv envVar
maybe (return False) (parseAsBool . T.toLower) mVal
printVersion :: RavenMode -> IO ()
printVersion = \case
ROVersion -> putStrLn versionLine >> exitSuccess
_ -> return ()
where
truthVals = ["true", "t", "yes", "y"]
falseVals = ["false", "f", "no", "n"]

parseAsBool t
| t `elem` truthVals = return True
| t `elem` falseVals = return False
| otherwise = putStrLn errMsg >> exitFailure

errMsg = "Fatal Error: " ++ envVar
++ " is not valid boolean text. " ++ "True values are "
++ show truthVals ++ " and False values are " ++ show falseVals
++ ". All values are case insensitive"
versionLine = "Hasura GraphQL Engine: " ++ T.unpack currentVersion

main :: IO ()
main = do
(RavenOptions rci ravenMode) <- parseArgs
mEnvDbUrl <- lookupEnv "HASURA_GRAPHQL_DATABASE_URL"
env <- getEnvironment
(RavenOptions rci ravenMode) <- parseArgs env
printVersion ravenMode
ci <- either ((>> exitFailure) . putStrLn . connInfoErrModifier)
return $ mkConnInfo mEnvDbUrl rci
return $ mkConnInfo rci
printConnInfo ci
loggerCtx <- mkLoggerCtx $ defaultLoggerSettings True
hloggerCtx <- mkLoggerCtx $ defaultLoggerSettings False
httpManager <- HTTP.newManager HTTP.tlsManagerSettings
case ravenMode of
ROServe (ServeOptions mPort cp isoL mRootDir mAccessKey authHookC mJwtSecret
ROServe (ServeOptions port cp isoL mRootDir mAccessKey mAuthHook mJwtSecret
mUnAuthRole corsCfg enableConsole) -> do

-- get all auth mode related config
mFinalAccessKey <- considerEnv "HASURA_GRAPHQL_ACCESS_KEY" $ getAccessKey <$> mAccessKey
mFinalAuthHook <- mkAuthHook authHookC
mFinalJwtSecret <- considerEnv "HASURA_GRAPHQL_JWT_SECRET" mJwtSecret
mFinalUnAuthRole <- considerEnv "HASURA_GRAPHQL_UNAUTHORIZED_ROLE" $ getRoleTxt <$> mUnAuthRole
defaultPort <- getFromEnv 8080 "HASURA_GRAPHQL_SERVER_PORT"
let port = fromMaybe defaultPort mPort
-- prepare auth mode
-- use webhook post config
authModeRes <- runExceptT $ mkAuthMode (AccessKey <$> mFinalAccessKey)
mFinalAuthHook
mFinalJwtSecret
(RoleName <$> mFinalUnAuthRole)
httpManager
loggerCtx
authModeRes <- runExceptT $ mkAuthMode mAccessKey mAuthHook mJwtSecret
mUnAuthRole httpManager loggerCtx

am <- either ((>> exitFailure) . putStrLn . T.unpack) return authModeRes
finalCorsDomain <- fromMaybe "*" <$> considerEnv "HASURA_GRAPHQL_CORS_DOMAIN" (ccDomain corsCfg)
let finalCorsCfg = CorsConfigG finalCorsDomain $ ccDisabled corsCfg
-- enable console config
finalEnableConsole <-
considerBoolEnv "HASURA_GRAPHQL_ENABLE_CONSOLE" enableConsole
-- init catalog if necessary
initialise ci httpManager
-- migrate catalog if necessary
migrate ci httpManager
prepareEvents ci
pool <- Q.initPGPool ci cp
putStrLn $ "server: running on port " ++ show port
(app, cacheRef) <- mkWaiApp isoL mRootDir loggerCtx pool httpManager
am finalCorsCfg finalEnableConsole
am corsCfg enableConsole
let warpSettings = Warp.setPort port Warp.defaultSettings
-- Warp.setHost "*" Warp.defaultSettings

Expand Down Expand Up @@ -190,6 +176,7 @@ main = do
queryBs <- BL.getContents
res <- runAsAdmin ci httpManager $ execQuery queryBs
either ((>> exitFailure) . printJSON) BLC.putStrLn res
ROVersion -> return ()
where
runTx :: Q.ConnInfo -> Q.TxE QErr a -> IO (Either QErr a)
runTx ci tx = do
Expand Down Expand Up @@ -235,24 +222,3 @@ main = do
++ "\n Port: " ++ show (Q.connPort ci)
++ "\n User: " ++ Q.connUser ci
++ "\n Database: " ++ Q.connDatabase ci

mkAuthHook (AuthHookG mUrl mTy) = do
url <- considerEnv "HASURA_GRAPHQL_AUTH_HOOK" mUrl
ty <- maybe getHookTypeEnv return mTy
return $ AuthHookG <$> url <*> pure ty

getHookTypeEnv = do
let envVar = "HASURA_GRAPHQL_AUTH_HOOK_MODE"
errorFn s = putStrLn (s ++ " for Env " ++ envVar)
>> exitFailure
mEnvVal <- lookupEnv "HASURA_GRAPHQL_AUTH_HOOK_MODE"
case mEnvVal of
Just s -> either errorFn return $ readHookType s
Nothing -> return AHTGet

-- if flags given are Nothing consider it's value from Env
considerEnv _ (Just t) = return $ Just t
considerEnv e Nothing = fmap T.pack <$> lookupEnv e

considerBoolEnv envVar =
bool (parseEnvAsBool envVar) (return True)
5 changes: 3 additions & 2 deletions server/src-lib/Hasura/Prelude.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import Data.Bool as M (bool)
import Data.Either as M (lefts, partitionEithers, rights)
import Data.Foldable as M (toList)
import Data.Hashable as M (Hashable)
import Data.List as M (find, foldl', group, sort, sortBy,
sortOn, union)
import Data.List as M (find, foldl', group, intercalate,
lookup, sort, sortBy, sortOn,
union)
import Data.Maybe as M (catMaybes, fromMaybe, isJust,
isNothing, listToMaybe, mapMaybe,
maybeToList)
Expand Down
17 changes: 6 additions & 11 deletions server/src-lib/Hasura/Server/Auth.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ module Hasura.Server.Auth
, mkAuthMode
, AccessKey (..)
, AuthHookType(..)
, AuthHookG (..)
, AuthHookConf
, AuthHook
, AuthHook (..)
-- JWT related
, RawJWT
, JWTConfig (..)
Expand Down Expand Up @@ -55,15 +53,12 @@ data AuthHookType
| AHTPost
deriving (Show, Eq)

data AuthHookG a b
= AuthHookG
{ ahUrl :: !a
, ahType :: !b
data AuthHook
= AuthHook
{ ahUrl :: !T.Text
, ahType :: !AuthHookType
} deriving (Show, Eq)

type AuthHookConf = AuthHookG (Maybe T.Text) (Maybe AuthHookType)
type AuthHook = AuthHookG T.Text AuthHookType

data AuthMode
= AMNoAuth
| AMAccessKey !AccessKey !(Maybe RoleName)
Expand Down Expand Up @@ -197,7 +192,7 @@ userInfoFromAuthHook logger manager hook reqHeaders = do
mkUserInfoFromResp logger urlT method status respBody
where
mkOptions = wreqOptions manager
AuthHookG urlT ty = hook
AuthHook urlT ty = hook
isPost = case ty of
AHTPost -> True
AHTGet -> False
Expand Down
Loading