2013-07-28 16:19:08 +04:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
{-# LANGUAGE RecordWildCards #-}
|
2012-05-11 08:38:05 +04:00
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
2013-07-28 16:19:08 +04:00
|
|
|
{-# LANGUAGE TemplateHaskell #-}
|
2012-05-11 08:38:05 +04:00
|
|
|
module Keter.App
|
|
|
|
( App
|
2013-07-26 11:09:11 +04:00
|
|
|
, AppStartConfig (..)
|
2012-05-11 08:38:05 +04:00
|
|
|
, start
|
|
|
|
, reload
|
2013-07-26 11:09:11 +04:00
|
|
|
, getTimestamp
|
2012-05-11 08:38:05 +04:00
|
|
|
, Keter.App.terminate
|
|
|
|
) where
|
|
|
|
|
2013-07-28 16:19:08 +04:00
|
|
|
import Codec.Archive.TempTarball
|
|
|
|
import Control.Applicative ((<$>))
|
|
|
|
import Control.Arrow ((***))
|
|
|
|
import Control.Concurrent.STM
|
|
|
|
import Control.Exception (bracketOnError, throwIO)
|
|
|
|
import qualified Data.Conduit.LogFile as LogFile
|
|
|
|
import Data.Conduit.Process.Unix (MonitoredProcess, ProcessTracker,
|
|
|
|
RotatingLog, monitorProcess,
|
|
|
|
terminateMonitoredProcess)
|
|
|
|
import qualified Data.Map as Map
|
|
|
|
import Data.Monoid ((<>))
|
|
|
|
import qualified Data.Set as Set
|
|
|
|
import Data.Text (pack)
|
|
|
|
import Data.Text.Encoding (decodeUtf8With, encodeUtf8)
|
|
|
|
import Data.Text.Encoding.Error (lenientDecode)
|
|
|
|
import qualified Data.Vector as V
|
|
|
|
import Data.Yaml
|
|
|
|
import Data.Yaml.FilePath
|
2013-07-28 20:34:15 +04:00
|
|
|
import Filesystem (removeTree, isFile, canonicalizePath)
|
2012-05-14 11:15:50 +04:00
|
|
|
import qualified Filesystem.Path.CurrentOS as F
|
2013-07-28 16:19:08 +04:00
|
|
|
import Keter.HostManager hiding (start)
|
|
|
|
import Keter.PortPool (PortPool, getPort, releasePort)
|
|
|
|
import Keter.Types
|
|
|
|
import Prelude hiding (FilePath)
|
|
|
|
import System.Posix.Types (EpochTime)
|
|
|
|
import System.Posix.Types (GroupID, UserID)
|
2013-07-28 20:34:15 +04:00
|
|
|
import System.Posix.Files (fileAccess)
|
|
|
|
import System.IO (hClose)
|
|
|
|
import qualified Network
|
|
|
|
import Control.Exception (try, IOException)
|
|
|
|
import Data.Maybe (fromMaybe)
|
|
|
|
import Control.Concurrent (threadDelay)
|
|
|
|
import System.Timeout (timeout)
|
2012-10-21 09:07:26 +04:00
|
|
|
|
2013-07-28 16:19:08 +04:00
|
|
|
data App = App
|
|
|
|
{ appModTime :: !(TVar (Maybe EpochTime))
|
|
|
|
, appRunningWebApps :: ![RunningWebApp]
|
|
|
|
}
|
|
|
|
|
|
|
|
data RunningWebApp = RunningWebApp
|
|
|
|
{ rwaProcess :: !MonitoredProcess
|
2013-07-28 20:34:15 +04:00
|
|
|
, rwaPort :: !Port
|
2013-07-28 16:19:08 +04:00
|
|
|
}
|
2012-05-11 08:38:05 +04:00
|
|
|
|
2013-07-28 16:19:08 +04:00
|
|
|
unpackBundle :: AppStartConfig
|
2013-07-28 14:41:42 +04:00
|
|
|
-> FilePath
|
2013-07-28 16:19:08 +04:00
|
|
|
-> AppId
|
2013-07-28 14:41:42 +04:00
|
|
|
-> IO (FilePath, BundleConfig)
|
2013-07-28 16:19:08 +04:00
|
|
|
unpackBundle AppStartConfig {..} bundle aid = do
|
|
|
|
ascLog $ UnpackingBundle bundle
|
|
|
|
unpackTempTar (fmap snd ascSetuid) ascTempFolder bundle folderName $ \dir -> do
|
2013-07-10 15:09:14 +04:00
|
|
|
let configFP = dir F.</> "config" F.</> "keter.yaml"
|
2013-07-14 14:02:18 +04:00
|
|
|
mconfig <- decodeFileRelative configFP
|
2013-07-10 15:09:14 +04:00
|
|
|
config <-
|
|
|
|
case mconfig of
|
2013-07-14 14:02:18 +04:00
|
|
|
Right config -> return config
|
|
|
|
Left e -> throwIO $ InvalidConfigFile e
|
2013-07-25 15:10:09 +04:00
|
|
|
return (dir, config)
|
2013-07-28 16:19:08 +04:00
|
|
|
where
|
|
|
|
folderName =
|
|
|
|
case aid of
|
|
|
|
AIBuiltin -> "__builtin__"
|
|
|
|
AINamed x -> x
|
2012-10-12 14:59:46 +04:00
|
|
|
|
2013-07-26 11:09:11 +04:00
|
|
|
data AppStartConfig = AppStartConfig
|
2013-07-28 16:19:08 +04:00
|
|
|
{ ascTempFolder :: !TempFolder
|
|
|
|
, ascSetuid :: !(Maybe (Text, (UserID, GroupID)))
|
2013-07-26 11:09:11 +04:00
|
|
|
, ascProcessTracker :: !ProcessTracker
|
2013-07-28 16:19:08 +04:00
|
|
|
, ascHostManager :: !HostManager
|
|
|
|
, ascPortPool :: !PortPool
|
|
|
|
, ascPlugins :: !Plugins
|
|
|
|
, ascLog :: !(LogMessage -> IO ())
|
|
|
|
, ascKeterConfig :: !KeterConfig
|
2013-07-26 11:09:11 +04:00
|
|
|
}
|
|
|
|
|
2013-07-28 16:19:08 +04:00
|
|
|
withConfig :: AppStartConfig
|
|
|
|
-> AppId
|
|
|
|
-> AppInput
|
|
|
|
-> (FilePath -> BundleConfig -> Maybe EpochTime -> IO a)
|
|
|
|
-> IO a
|
|
|
|
withConfig _asc _aid (AIData bconfig) f = f "/tmp" bconfig Nothing
|
|
|
|
withConfig asc aid (AIBundle fp modtime) f = bracketOnError
|
|
|
|
(unpackBundle asc fp aid)
|
|
|
|
(\(newdir, _) -> removeTree newdir)
|
|
|
|
$ \(newdir, bconfig) -> f newdir bconfig (Just modtime)
|
2013-07-26 11:09:11 +04:00
|
|
|
|
2013-07-28 16:19:08 +04:00
|
|
|
withReservations :: AppStartConfig
|
|
|
|
-> AppId
|
|
|
|
-> BundleConfig
|
|
|
|
-> ([WebAppConfig Port] -> Map Host ProxyAction -> IO a)
|
|
|
|
-> IO a
|
|
|
|
withReservations asc aid bconfig f = withActions asc bconfig $ \wacs actions -> bracketOnError
|
|
|
|
(reserveHosts (ascHostManager asc) aid $ Map.keysSet actions)
|
|
|
|
(forgetReservations (ascHostManager asc) aid)
|
|
|
|
(const $ f wacs actions)
|
|
|
|
|
|
|
|
withActions :: AppStartConfig
|
|
|
|
-> BundleConfig
|
|
|
|
-> ([WebAppConfig Port] -> Map Host ProxyAction -> IO a)
|
|
|
|
-> IO a
|
|
|
|
withActions asc bconfig f =
|
|
|
|
loop (V.toList $ bconfigStanzas bconfig) [] Map.empty
|
|
|
|
where
|
|
|
|
loop [] wacs actions = f wacs actions
|
|
|
|
loop (StanzaWebApp wac:stanzas) wacs actions = bracketOnError
|
|
|
|
(getPort (ascLog asc) (ascPortPool asc) >>= either throwIO return)
|
|
|
|
(releasePort (ascPortPool asc))
|
|
|
|
(\port -> loop
|
|
|
|
stanzas
|
|
|
|
(wac { waconfigPort = port } : wacs)
|
|
|
|
(Map.unions $ actions : map (\host -> Map.singleton host $ PAPort port) hosts))
|
|
|
|
where
|
|
|
|
hosts = Set.toList $ Set.insert (waconfigApprootHost wac) (waconfigHosts wac)
|
|
|
|
loop (StanzaStaticFiles sfc:stanzas) wacs actions0 =
|
|
|
|
loop stanzas wacs actions
|
|
|
|
where
|
|
|
|
actions = Map.unions
|
|
|
|
$ actions0
|
|
|
|
: map (\host -> Map.singleton host $ PAStatic sfc)
|
|
|
|
(Set.toList (sfconfigHosts sfc))
|
|
|
|
loop (StanzaRedirect red:stanzas) wacs actions0 =
|
|
|
|
loop stanzas wacs actions
|
|
|
|
where
|
|
|
|
actions = Map.unions
|
|
|
|
$ actions0
|
|
|
|
: map (\host -> Map.singleton host $ PARedirect red)
|
|
|
|
(Set.toList (redirconfigHosts red))
|
|
|
|
loop (StanzaReverseProxy rev:stanzas) wacs actions0 =
|
|
|
|
loop stanzas wacs actions
|
|
|
|
where
|
|
|
|
actions = Map.insert (reversingHost rev) (PAReverseProxy rev) actions0
|
|
|
|
|
|
|
|
withRotatingLog :: AppStartConfig
|
|
|
|
-> AppId
|
|
|
|
-> (RotatingLog -> IO a)
|
|
|
|
-> IO a
|
|
|
|
withRotatingLog AppStartConfig {..} aid = bracketOnError
|
|
|
|
(LogFile.openRotatingLog (F.encodeString dir) LogFile.defaultMaxTotal)
|
|
|
|
LogFile.close
|
|
|
|
where
|
|
|
|
dir = kconfigDir ascKeterConfig F.</> "log" F.</> name
|
|
|
|
name =
|
|
|
|
case aid of
|
|
|
|
AIBuiltin -> "__builtin__"
|
|
|
|
AINamed x -> F.fromText $ "app-" <> x
|
2013-07-26 11:09:11 +04:00
|
|
|
|
2013-07-28 20:34:15 +04:00
|
|
|
withSanityChecks :: AppStartConfig -> BundleConfig -> IO a -> IO a
|
|
|
|
withSanityChecks AppStartConfig {..} BundleConfig {..} f = do
|
|
|
|
V.mapM_ go bconfigStanzas
|
|
|
|
ascLog SanityChecksPassed
|
|
|
|
f
|
|
|
|
where
|
|
|
|
go (StanzaWebApp WebAppConfig {..}) = do
|
|
|
|
exists <- isFile waconfigExec
|
|
|
|
if exists
|
|
|
|
then do
|
|
|
|
canExec <- fileAccess (F.encodeString waconfigExec) True False True
|
|
|
|
if canExec
|
|
|
|
then return ()
|
|
|
|
else throwIO $ FileNotExecutable waconfigExec
|
|
|
|
else throwIO $ ExecutableNotFound waconfigExec
|
|
|
|
go _ = return ()
|
|
|
|
|
2013-07-26 11:09:11 +04:00
|
|
|
start :: AppStartConfig
|
|
|
|
-> AppId
|
2013-07-28 16:19:08 +04:00
|
|
|
-> AppInput
|
2013-07-28 14:41:42 +04:00
|
|
|
-> IO App
|
2013-07-28 16:19:08 +04:00
|
|
|
start asc aid input =
|
|
|
|
withConfig asc aid input $ \newdir bconfig mmodtime ->
|
2013-07-28 20:34:15 +04:00
|
|
|
withSanityChecks asc bconfig $
|
2013-07-28 16:19:08 +04:00
|
|
|
withReservations asc aid bconfig $ \webapps actions ->
|
|
|
|
withRotatingLog asc aid $ \rlog ->
|
|
|
|
withWebApps asc aid bconfig newdir rlog webapps $ \runningWebapps -> do
|
|
|
|
mapM_ ensureAlive runningWebapps
|
|
|
|
activateApp (ascHostManager asc) aid actions
|
|
|
|
tmodtime <- newTVarIO mmodtime
|
|
|
|
return App
|
|
|
|
{ appModTime = tmodtime
|
|
|
|
, appRunningWebApps = runningWebapps
|
|
|
|
}
|
|
|
|
|
|
|
|
withWebApps :: AppStartConfig
|
|
|
|
-> AppId
|
|
|
|
-> BundleConfig
|
|
|
|
-> FilePath
|
|
|
|
-> RotatingLog
|
|
|
|
-> [WebAppConfig Port]
|
|
|
|
-> ([RunningWebApp] -> IO a)
|
|
|
|
-> IO a
|
|
|
|
withWebApps asc aid bconfig dir rlog configs0 f =
|
|
|
|
loop configs0 id
|
|
|
|
where
|
|
|
|
loop [] front = f $ front []
|
|
|
|
loop (c:cs) front = bracketOnError
|
|
|
|
(launchWebApp asc aid bconfig dir rlog c)
|
|
|
|
killWebApp
|
|
|
|
(\rwa -> loop cs (front . (rwa:)))
|
|
|
|
|
|
|
|
launchWebApp :: AppStartConfig
|
|
|
|
-> AppId
|
|
|
|
-> BundleConfig
|
|
|
|
-> FilePath
|
|
|
|
-> RotatingLog
|
|
|
|
-> WebAppConfig Port
|
|
|
|
-> IO RunningWebApp
|
|
|
|
launchWebApp AppStartConfig {..} aid BundleConfig {..} dir rlog WebAppConfig {..} = do
|
|
|
|
otherEnv <- pluginsGetEnv ascPlugins name bconfigRaw
|
|
|
|
let env = ("PORT", pack $ show waconfigPort)
|
|
|
|
: ("APPROOT", (if waconfigSsl then "https://" else "http://") <> waconfigApprootHost)
|
|
|
|
: otherEnv
|
2013-07-28 20:34:15 +04:00
|
|
|
exec <- canonicalizePath waconfigExec
|
2013-07-28 16:19:08 +04:00
|
|
|
bracketOnError
|
|
|
|
(monitorProcess
|
|
|
|
(ascLog . OtherMessage . decodeUtf8With lenientDecode)
|
|
|
|
ascProcessTracker
|
|
|
|
(encodeUtf8 . fst <$> ascSetuid)
|
2013-07-28 20:34:15 +04:00
|
|
|
(encodeUtf8 $ either id id $ F.toText exec)
|
2013-07-28 16:19:08 +04:00
|
|
|
(encodeUtf8 $ either id id $ F.toText dir)
|
|
|
|
(map encodeUtf8 $ V.toList waconfigArgs)
|
|
|
|
(map (encodeUtf8 *** encodeUtf8) env)
|
|
|
|
rlog)
|
|
|
|
terminateMonitoredProcess
|
|
|
|
$ \mp -> do
|
|
|
|
return RunningWebApp
|
|
|
|
{ rwaProcess = mp
|
2013-07-28 20:34:15 +04:00
|
|
|
, rwaPort = waconfigPort
|
2013-07-28 16:19:08 +04:00
|
|
|
}
|
|
|
|
where
|
|
|
|
name =
|
|
|
|
case aid of
|
|
|
|
AIBuiltin -> "__builtin__"
|
|
|
|
AINamed x -> x
|
|
|
|
|
|
|
|
killWebApp :: RunningWebApp -> IO ()
|
2013-07-28 21:02:28 +04:00
|
|
|
killWebApp RunningWebApp {..} = do
|
|
|
|
terminateMonitoredProcess rwaProcess
|
2013-07-28 16:19:08 +04:00
|
|
|
|
|
|
|
ensureAlive :: RunningWebApp -> IO ()
|
2013-07-28 20:34:15 +04:00
|
|
|
ensureAlive RunningWebApp {..} = do
|
|
|
|
didAnswer <- testApp rwaPort
|
|
|
|
if didAnswer
|
|
|
|
then return ()
|
|
|
|
else error "ensureAlive failed"
|
2013-07-28 16:19:08 +04:00
|
|
|
where
|
2013-07-28 20:34:15 +04:00
|
|
|
testApp :: Port -> IO Bool
|
|
|
|
testApp port = do
|
|
|
|
res <- timeout (90 * 1000 * 1000) testApp'
|
|
|
|
return $ fromMaybe False res
|
|
|
|
where
|
|
|
|
testApp' = do
|
|
|
|
threadDelay $ 2 * 1000 * 1000
|
|
|
|
eres <- try $ Network.connectTo "127.0.0.1" $ Network.PortNumber $ fromIntegral port
|
|
|
|
case eres of
|
|
|
|
Left (_ :: IOException) -> testApp'
|
|
|
|
Right handle -> do
|
|
|
|
hClose handle
|
|
|
|
return True
|
2013-07-26 11:09:11 +04:00
|
|
|
|
|
|
|
{-
|
2012-05-11 08:38:05 +04:00
|
|
|
start :: TempFolder
|
2012-10-24 18:31:18 +04:00
|
|
|
-> Maybe (Text, (UserID, GroupID))
|
2012-11-19 12:31:35 +04:00
|
|
|
-> ProcessTracker
|
2013-07-25 14:07:48 +04:00
|
|
|
-> HostManager
|
2013-07-10 14:26:37 +04:00
|
|
|
-> Plugins
|
2013-07-10 13:48:46 +04:00
|
|
|
-> RotatingLog
|
2012-05-11 12:29:25 +04:00
|
|
|
-> Appname
|
2013-07-26 11:09:11 +04:00
|
|
|
-> (Maybe BundleConfig)
|
2012-05-15 12:19:03 +04:00
|
|
|
-> KIO () -- ^ action to perform to remove this App from list of actives
|
|
|
|
-> KIO (App, KIO ())
|
2013-07-10 14:26:37 +04:00
|
|
|
start tf muid processTracker portman plugins rlog appname bundle removeFromList = do
|
2013-07-25 15:10:09 +04:00
|
|
|
Prelude.error "FIXME Keter.App.start"
|
2012-05-15 12:19:03 +04:00
|
|
|
chan <- newChan
|
|
|
|
return (App $ writeChan chan, rest chan)
|
2012-05-11 08:38:05 +04:00
|
|
|
where
|
|
|
|
|
2012-05-15 12:19:03 +04:00
|
|
|
rest chan = forkKIO $ do
|
2012-10-24 18:31:18 +04:00
|
|
|
mres <- unpackBundle tf (snd <$> muid) bundle appname
|
2012-05-11 08:38:05 +04:00
|
|
|
case mres of
|
2012-05-15 12:19:03 +04:00
|
|
|
Left e -> do
|
2012-05-17 10:32:11 +04:00
|
|
|
$logEx e
|
2012-05-15 12:19:03 +04:00
|
|
|
removeFromList
|
|
|
|
Right (dir, config) -> do
|
2013-01-28 11:09:02 +04:00
|
|
|
let common = do
|
2013-07-14 16:28:48 +04:00
|
|
|
mapM_ (\StaticHost{..} -> addEntry portman shHost (PEStatic shRoot)) $ Set.toList $ bconfigStaticHosts config
|
|
|
|
mapM_ (\Redirect{..} -> addEntry portman redFrom (PERedirect $ encodeUtf8 redTo)) $ Set.toList $ bconfigRedirects config
|
|
|
|
case bconfigApp config of
|
2013-01-28 11:09:02 +04:00
|
|
|
Nothing -> do
|
|
|
|
common
|
|
|
|
loop chan dir config Nothing
|
|
|
|
Just appconfig -> do
|
|
|
|
eport <- getPort portman
|
|
|
|
case eport of
|
|
|
|
Left e -> do
|
|
|
|
$logEx e
|
2012-05-15 11:49:20 +04:00
|
|
|
removeFromList
|
2013-01-28 11:09:02 +04:00
|
|
|
Right port -> do
|
2013-07-14 17:28:43 +04:00
|
|
|
eprocess <- runApp port dir appconfig
|
|
|
|
case eprocess of
|
|
|
|
Left e -> do
|
|
|
|
$logEx e
|
2013-01-28 11:09:02 +04:00
|
|
|
removeFromList
|
2013-07-14 17:28:43 +04:00
|
|
|
Right process -> do
|
|
|
|
b <- testApp port
|
|
|
|
if b
|
|
|
|
then do
|
|
|
|
addEntry portman (aconfigHost appconfig) $ PEPort port
|
|
|
|
mapM_ (flip (addEntry portman) $ PEPort port) $ Set.toList $ aconfigExtraHosts appconfig
|
|
|
|
common
|
|
|
|
loop chan dir config $ Just (process, port)
|
|
|
|
else do
|
|
|
|
removeFromList
|
|
|
|
releasePort portman port
|
|
|
|
void $ liftIO $ terminateMonitoredProcess process
|
2012-05-11 08:38:05 +04:00
|
|
|
|
2013-01-28 11:09:02 +04:00
|
|
|
loop chan dirOld configOld mprocPortOld = do
|
2012-05-15 12:19:03 +04:00
|
|
|
command <- readChan chan
|
2012-05-11 08:38:05 +04:00
|
|
|
case command of
|
|
|
|
Terminate -> do
|
|
|
|
removeFromList
|
2013-07-14 16:28:48 +04:00
|
|
|
case bconfigApp configOld of
|
2013-01-28 11:09:02 +04:00
|
|
|
Nothing -> return ()
|
|
|
|
Just appconfig -> do
|
2013-07-14 16:28:48 +04:00
|
|
|
removeEntry portman $ aconfigHost appconfig
|
|
|
|
mapM_ (removeEntry portman) $ Set.toList $ aconfigExtraHosts appconfig
|
|
|
|
mapM_ (removeEntry portman) $ map shHost $ Set.toList $ bconfigStaticHosts configOld
|
|
|
|
mapM_ (removeEntry portman) $ map redFrom $ Set.toList $ bconfigRedirects configOld
|
2012-05-15 12:19:03 +04:00
|
|
|
log $ TerminatingApp appname
|
2012-05-11 08:38:05 +04:00
|
|
|
terminateOld
|
|
|
|
Reload -> do
|
2012-10-24 18:31:18 +04:00
|
|
|
mres <- unpackBundle tf (snd <$> muid) bundle appname
|
2012-05-11 08:38:05 +04:00
|
|
|
case mres of
|
2012-05-15 12:19:03 +04:00
|
|
|
Left e -> do
|
|
|
|
log $ InvalidBundle bundle e
|
2013-01-28 11:09:02 +04:00
|
|
|
loop chan dirOld configOld mprocPortOld
|
2012-05-15 12:19:03 +04:00
|
|
|
Right (dir, config) -> do
|
2012-08-06 18:44:41 +04:00
|
|
|
eport <- getPort portman
|
2012-05-15 11:49:20 +04:00
|
|
|
case eport of
|
2012-05-17 10:32:11 +04:00
|
|
|
Left e -> $logEx e
|
2012-05-15 11:49:20 +04:00
|
|
|
Right port -> do
|
2013-01-28 11:09:02 +04:00
|
|
|
let common = do
|
2013-07-14 16:28:48 +04:00
|
|
|
mapM_ (\StaticHost{..} -> addEntry portman shHost (PEStatic shRoot)) $ Set.toList $ bconfigStaticHosts config
|
|
|
|
mapM_ (\Redirect{..} -> addEntry portman redFrom (PERedirect $ encodeUtf8 redTo)) $ Set.toList $ bconfigRedirects config
|
|
|
|
case bconfigApp config of
|
2013-01-28 11:09:02 +04:00
|
|
|
Nothing -> do
|
|
|
|
common
|
|
|
|
loop chan dir config Nothing
|
|
|
|
Just appconfig -> do
|
2013-07-14 17:28:43 +04:00
|
|
|
eprocess <- runApp port dir appconfig
|
|
|
|
mprocess <-
|
|
|
|
case eprocess of
|
|
|
|
Left _ -> return Nothing
|
|
|
|
Right process -> do
|
|
|
|
b <- testApp port
|
|
|
|
return $ if b
|
|
|
|
then Just process
|
|
|
|
else Nothing
|
|
|
|
case mprocess of
|
|
|
|
Just process -> do
|
2013-07-14 16:28:48 +04:00
|
|
|
addEntry portman (aconfigHost appconfig) $ PEPort port
|
|
|
|
mapM_ (flip (addEntry portman) $ PEPort port) $ Set.toList $ aconfigExtraHosts appconfig
|
2013-01-28 11:09:02 +04:00
|
|
|
common
|
2013-07-14 16:28:48 +04:00
|
|
|
case bconfigApp configOld of
|
|
|
|
Just appconfigOld | aconfigHost appconfig /= aconfigHost appconfigOld ->
|
|
|
|
removeEntry portman $ aconfigHost appconfigOld
|
2013-01-28 11:09:02 +04:00
|
|
|
_ -> return ()
|
|
|
|
log $ FinishedReloading appname
|
|
|
|
terminateOld
|
|
|
|
loop chan dir config $ Just (process, port)
|
2013-07-14 17:28:43 +04:00
|
|
|
Nothing -> do
|
2013-01-28 11:09:02 +04:00
|
|
|
releasePort portman port
|
2013-07-14 17:28:43 +04:00
|
|
|
case eprocess of
|
|
|
|
Left _ -> return ()
|
|
|
|
Right process -> void $ liftIO $ terminateMonitoredProcess process
|
2013-01-28 11:09:02 +04:00
|
|
|
log $ ProcessDidNotStart bundle
|
|
|
|
loop chan dirOld configOld mprocPortOld
|
2012-05-11 08:38:05 +04:00
|
|
|
where
|
2012-05-15 12:19:03 +04:00
|
|
|
terminateOld = forkKIO $ do
|
2012-05-11 08:38:05 +04:00
|
|
|
threadDelay $ 20 * 1000 * 1000
|
2012-05-15 12:19:03 +04:00
|
|
|
log $ TerminatingOldProcess appname
|
2013-01-28 11:09:02 +04:00
|
|
|
case mprocPortOld of
|
|
|
|
Nothing -> return ()
|
2013-07-14 17:28:43 +04:00
|
|
|
Just (processOld, _) -> void $ liftIO $ terminateMonitoredProcess processOld
|
2012-05-11 08:38:05 +04:00
|
|
|
threadDelay $ 60 * 1000 * 1000
|
2012-05-15 12:19:03 +04:00
|
|
|
log $ RemovingOldFolder dirOld
|
|
|
|
res <- liftIO $ removeTree dirOld
|
|
|
|
case res of
|
2012-05-17 10:32:11 +04:00
|
|
|
Left e -> $logEx e
|
2012-05-15 12:19:03 +04:00
|
|
|
Right () -> return ()
|
2013-07-25 15:10:09 +04:00
|
|
|
-}
|
2012-05-14 12:03:57 +04:00
|
|
|
|
2013-07-28 14:41:42 +04:00
|
|
|
reload :: App -> AppInput -> IO ()
|
2013-07-28 16:19:08 +04:00
|
|
|
reload = error "FIXME"
|
2012-05-11 08:38:05 +04:00
|
|
|
|
2013-07-28 14:41:42 +04:00
|
|
|
terminate :: App -> IO ()
|
2013-07-28 16:19:08 +04:00
|
|
|
terminate = error "FIXME"
|
2013-07-10 14:26:37 +04:00
|
|
|
|
2013-07-26 11:09:11 +04:00
|
|
|
-- | Get the modification time of the bundle file this app was launched from,
|
|
|
|
-- if relevant.
|
|
|
|
getTimestamp :: App -> STM (Maybe EpochTime)
|
|
|
|
getTimestamp _ = return Nothing -- FIXME
|
|
|
|
|
2013-07-28 16:19:08 +04:00
|
|
|
pluginsGetEnv :: Plugins -> Appname -> Object -> IO [(Text, Text)]
|
|
|
|
pluginsGetEnv ps app o = fmap concat $ mapM (\p -> pluginGetEnv p app o) ps
|
2013-07-25 18:35:16 +04:00
|
|
|
|
|
|
|
{- FIXME handle static stanzas
|
|
|
|
let staticReverse r = do
|
|
|
|
HostMan.addEntry hostman (ReverseProxy.reversingHost r)
|
|
|
|
$ HostMan.PEReverseProxy
|
|
|
|
$ ReverseProxy.RPEntry r manager
|
|
|
|
runKIO' $ mapM_ staticReverse (Set.toList kconfigReverseProxy)
|
|
|
|
-}
|
2013-07-26 11:09:11 +04:00
|
|
|
|
|
|
|
{- FIXME
|
|
|
|
rest <-
|
|
|
|
case Map.lookup appname appMap of
|
|
|
|
Just (app, _time) -> do
|
|
|
|
App.reload app
|
|
|
|
etime <- liftIO $ modificationTime <$> getFileStatus (F.encodeString bundle)
|
|
|
|
let time = either (P.const 0) id etime
|
|
|
|
return (Map.insert appname (app, time) appMap, return ())
|
|
|
|
Nothing -> do
|
|
|
|
mlogger <- do
|
|
|
|
let dirout = kconfigDir </> "log" </> fromText ("app-" ++ appname)
|
|
|
|
direrr = dirout </> "err"
|
|
|
|
erlog <- liftIO $ LogFile.openRotatingLog
|
|
|
|
(F.encodeString dirout)
|
|
|
|
LogFile.defaultMaxTotal
|
|
|
|
case erlog of
|
|
|
|
Left e -> do
|
|
|
|
$logEx e
|
|
|
|
return Nothing
|
|
|
|
Right rlog -> return (Just rlog)
|
|
|
|
let logger = fromMaybe LogFile.dummy mlogger
|
|
|
|
(app, rest) <- App.start
|
|
|
|
tf
|
|
|
|
muid
|
|
|
|
processTracker
|
|
|
|
hostman
|
|
|
|
plugins
|
|
|
|
logger
|
|
|
|
appname
|
|
|
|
bundle
|
|
|
|
(removeApp appname)
|
|
|
|
etime <- liftIO $ modificationTime <$> getFileStatus (F.encodeString bundle)
|
|
|
|
let time = either (P.const 0) id etime
|
|
|
|
let appMap' = Map.insert appname (app, time) appMap
|
|
|
|
return (appMap', rest)
|
|
|
|
rest
|
|
|
|
-}
|