mirror of
https://github.com/snoyberg/keter.git
synced 2024-12-14 08:05:40 +03:00
Merge pull request #105 from bermanjosh/remote-postgres
Remote postgres
This commit is contained in:
commit
9781b49451
@ -8,7 +8,7 @@ module Keter.Plugin.Postgres
|
|||||||
, load
|
, load
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Applicative ((<$>), (<*>))
|
import Control.Applicative ((<$>), (<*>), pure)
|
||||||
import Control.Concurrent (forkIO)
|
import Control.Concurrent (forkIO)
|
||||||
import Control.Concurrent.Chan
|
import Control.Concurrent.Chan
|
||||||
import Control.Concurrent.MVar
|
import Control.Concurrent.MVar
|
||||||
@ -20,10 +20,12 @@ import qualified Data.Char as C
|
|||||||
import Data.Default
|
import Data.Default
|
||||||
import qualified Data.HashMap.Strict as HMap
|
import qualified Data.HashMap.Strict as HMap
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
import Data.Maybe (fromMaybe)
|
||||||
import Data.Monoid ((<>))
|
import Data.Monoid ((<>))
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Lazy as TL
|
import qualified Data.Text.Lazy as TL
|
||||||
import Data.Text.Lazy.Builder (fromText, toLazyText)
|
import Data.Text.Lazy.Builder (fromText, toLazyText)
|
||||||
|
import qualified Data.Vector as V
|
||||||
import Data.Yaml
|
import Data.Yaml
|
||||||
import Keter.Types
|
import Keter.Types
|
||||||
import Prelude hiding (FilePath)
|
import Prelude hiding (FilePath)
|
||||||
@ -48,29 +50,47 @@ instance Default Settings where
|
|||||||
"';\nCREATE DATABASE " <> fromText dbiName <>
|
"';\nCREATE DATABASE " <> fromText dbiName <>
|
||||||
" OWNER " <> fromText dbiUser <>
|
" OWNER " <> fromText dbiUser <>
|
||||||
";"
|
";"
|
||||||
_ <- readProcess "sudo" ["-u", "postgres", "psql"] $ TL.unpack sql
|
(cmd, args)
|
||||||
|
| ( dbServer dbiServer == "localhost"
|
||||||
|
|| dbServer dbiServer == "127.0.0.1") =
|
||||||
|
("sudo", ["-u", "postgres", "psql"])
|
||||||
|
| otherwise =
|
||||||
|
("psql",
|
||||||
|
[ "-h", (T.unpack $ dbServer dbiServer)
|
||||||
|
, "-p", (show $ dbPort dbiServer)
|
||||||
|
, "-U", "postgres"])
|
||||||
|
_ <- readProcess cmd args $ TL.unpack sql
|
||||||
return ()
|
return ()
|
||||||
}
|
}
|
||||||
|
|
||||||
-- | Information on an individual PostgreSQL database.
|
-- | Information on an individual PostgreSQL database.
|
||||||
data DBInfo = DBInfo
|
data DBInfo = DBInfo
|
||||||
{ dbiName :: Text
|
{ dbiName :: Text
|
||||||
, dbiUser :: Text
|
, dbiUser :: Text
|
||||||
, dbiPass :: Text
|
, dbiPass :: Text
|
||||||
|
, dbiServer :: DBServerInfo
|
||||||
}
|
}
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
randomDBI :: R.StdGen -> (DBInfo, R.StdGen)
|
data DBServerInfo = DBServerInfo
|
||||||
randomDBI =
|
{ dbServer :: Text
|
||||||
S.runState (DBInfo <$> rt <*> rt <*> rt)
|
, dbPort :: Int
|
||||||
|
}
|
||||||
|
deriving Show
|
||||||
|
|
||||||
|
randomDBI :: DBServerInfo -> R.StdGen -> (DBInfo, R.StdGen)
|
||||||
|
randomDBI dbsi =
|
||||||
|
S.runState (DBInfo <$> rt <*> rt <*> rt <*> (pure dbsi))
|
||||||
where
|
where
|
||||||
rt = T.pack <$> replicateM 10 (S.state $ R.randomR ('a', 'z'))
|
rt = T.pack <$> replicateM 10 (S.state $ R.randomR ('a', 'z'))
|
||||||
|
|
||||||
instance ToJSON DBInfo where
|
instance ToJSON DBInfo where
|
||||||
toJSON (DBInfo n u p) = object
|
toJSON (DBInfo n u p (DBServerInfo server port)) = object
|
||||||
[ "name" .= n
|
[ "name" .= n
|
||||||
, "user" .= u
|
, "user" .= u
|
||||||
, "pass" .= p
|
, "pass" .= p
|
||||||
|
, "server" .= server
|
||||||
|
, "port" .= port
|
||||||
]
|
]
|
||||||
|
|
||||||
instance FromJSON DBInfo where
|
instance FromJSON DBInfo where
|
||||||
@ -78,9 +98,21 @@ instance FromJSON DBInfo where
|
|||||||
<$> o .: "name"
|
<$> o .: "name"
|
||||||
<*> o .: "user"
|
<*> o .: "user"
|
||||||
<*> o .: "pass"
|
<*> o .: "pass"
|
||||||
|
<*> (DBServerInfo
|
||||||
|
<$> o .:? "server" .!= "localhost"
|
||||||
|
<*> o .:? "port" .!= 5432)
|
||||||
parseJSON _ = mzero
|
parseJSON _ = mzero
|
||||||
|
|
||||||
data Command = GetConfig Appname (Either SomeException DBInfo -> IO ())
|
instance FromJSON DBServerInfo where
|
||||||
|
parseJSON (Object o) = DBServerInfo
|
||||||
|
<$> o .: "server"
|
||||||
|
<*> o .: "port"
|
||||||
|
parseJSON _ = mzero
|
||||||
|
|
||||||
|
instance Default DBServerInfo where
|
||||||
|
def = DBServerInfo "localhost" 5432
|
||||||
|
|
||||||
|
data Command = GetConfig Appname DBServerInfo (Either SomeException DBInfo -> IO ())
|
||||||
|
|
||||||
-- | Load a set of existing connections from a config file. If the file does
|
-- | Load a set of existing connections from a config file. If the file does
|
||||||
-- not exist, it will be created. Any newly created databases will
|
-- not exist, it will be created. Any newly created databases will
|
||||||
@ -104,24 +136,29 @@ load Settings{..} fp = do
|
|||||||
return Plugin
|
return Plugin
|
||||||
{ pluginGetEnv = \appname o ->
|
{ pluginGetEnv = \appname o ->
|
||||||
case HMap.lookup "postgres" o of
|
case HMap.lookup "postgres" o of
|
||||||
|
Just (Array v) -> do
|
||||||
|
let dbServer = fromMaybe def . parseMaybe parseJSON $ V.head v
|
||||||
|
doenv chan appname dbServer
|
||||||
Just (Bool True) -> do
|
Just (Bool True) -> do
|
||||||
x <- newEmptyMVar
|
doenv chan appname def
|
||||||
writeChan chan $ GetConfig appname $ putMVar x
|
|
||||||
edbi <- takeMVar x
|
|
||||||
edbiToEnv edbi
|
|
||||||
_ -> return []
|
_ -> return []
|
||||||
}
|
}
|
||||||
|
where doenv chan appname dbs = do
|
||||||
|
x <- newEmptyMVar
|
||||||
|
writeChan chan $ GetConfig appname dbs $ putMVar x
|
||||||
|
edbi <- takeMVar x
|
||||||
|
edbiToEnv edbi
|
||||||
|
|
||||||
tmpfp = fp <.> "tmp"
|
tmpfp = fp <.> "tmp"
|
||||||
|
|
||||||
loop chan = do
|
loop chan = do
|
||||||
GetConfig appname f <- lift $ readChan chan
|
GetConfig appname dbServer f <- lift $ readChan chan
|
||||||
(db, g) <- S.get
|
(db, g) <- S.get
|
||||||
dbi <-
|
dbi <-
|
||||||
case Map.lookup appname db of
|
case Map.lookup appname db of
|
||||||
Just dbi -> return $ Right dbi
|
Just dbi -> return $ Right dbi
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
let (dbi', g') = randomDBI g
|
let (dbi', g') = randomDBI dbServer g
|
||||||
let dbi = dbi'
|
let dbi = dbi'
|
||||||
{ dbiName = sanitize appname <> dbiName dbi'
|
{ dbiName = sanitize appname <> dbiName dbi'
|
||||||
, dbiUser = sanitize appname <> dbiUser dbi'
|
, dbiUser = sanitize appname <> dbiUser dbi'
|
||||||
@ -152,9 +189,10 @@ edbiToEnv :: Either SomeException DBInfo
|
|||||||
-> IO [(Text, Text)]
|
-> IO [(Text, Text)]
|
||||||
edbiToEnv (Left e) = throwIO e
|
edbiToEnv (Left e) = throwIO e
|
||||||
edbiToEnv (Right dbi) = return
|
edbiToEnv (Right dbi) = return
|
||||||
[ ("PGHOST", "localhost")
|
[ ("PGHOST", dbServer $ dbiServer dbi)
|
||||||
, ("PGPORT", "5432")
|
, ("PGPORT", T.pack . show . dbPort $ dbiServer dbi)
|
||||||
, ("PGUSER", dbiUser dbi)
|
, ("PGUSER", dbiUser dbi)
|
||||||
, ("PGPASS", dbiPass dbi)
|
, ("PGPASS", dbiPass dbi)
|
||||||
, ("PGDATABASE", dbiName dbi)
|
, ("PGDATABASE", dbiName dbi)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
20
README.md
Normal file → Executable file
20
README.md
Normal file → Executable file
@ -179,8 +179,26 @@ plugins:
|
|||||||
postgres: true
|
postgres: true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* Keter can be configured to connect to a remote postgres server using the following syntax:
|
||||||
|
```yaml
|
||||||
|
plugins:
|
||||||
|
postgres:
|
||||||
|
- server: remoteServerNameOrIP
|
||||||
|
port: 1234
|
||||||
|
```
|
||||||
|
|
||||||
|
Different webapps can be configured to use different servers using the above syntax.
|
||||||
|
It should be noted that keter will prioritize it's own postgres.yaml record for an app.
|
||||||
|
So if moving an existing app from a local postgres server to a remote one (or
|
||||||
|
switching remote servers), the postgres.yaml file will need to be updated manually.
|
||||||
|
|
||||||
|
Keter will connect to the remote servers using the `postgres` account. This setup
|
||||||
|
assumes the remote server's `pg_hba.conf` file has been configured to allow connections
|
||||||
|
from the keter-server IP using the `trust` method.
|
||||||
|
|
||||||
(Note: The `plugins` configuration option was added in v1.0 of the
|
(Note: The `plugins` configuration option was added in v1.0 of the
|
||||||
keter configuration syntax. If you are using v0.4 then use `postgres: true`.)
|
keter configuration syntax. If you are using v0.4 then use `postgres: true`.
|
||||||
|
The remote-postgres server syntax was added in v1.4.2.)
|
||||||
|
|
||||||
* Modify your application to get its database connection settings from the following environment variables:
|
* Modify your application to get its database connection settings from the following environment variables:
|
||||||
* `PGHOST`
|
* `PGHOST`
|
||||||
|
@ -67,3 +67,7 @@ stanzas:
|
|||||||
|
|
||||||
plugins:
|
plugins:
|
||||||
#postgres: true
|
#postgres: true
|
||||||
|
# Syntax for remote-DB server:
|
||||||
|
# postgres:
|
||||||
|
# - server: remoteServerNameOrIP
|
||||||
|
# port: 1234
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Name: keter
|
Name: keter
|
||||||
Version: 1.4.1
|
Version: 1.4.2
|
||||||
Synopsis: Web application deployment manager, focusing on Haskell web frameworks
|
Synopsis: Web application deployment manager, focusing on Haskell web frameworks
|
||||||
Description: Hackage documentation generation is not reliable. For up to date documentation, please see: <http://www.stackage.org/package/keter>.
|
Description: Hackage documentation generation is not reliable. For up to date documentation, please see: <http://www.stackage.org/package/keter>.
|
||||||
Homepage: http://www.yesodweb.com/
|
Homepage: http://www.yesodweb.com/
|
||||||
|
Loading…
Reference in New Issue
Block a user