packages feed

keter 1.3.4 → 1.3.5

raw patch · 6 files changed

+110/−63 lines, 6 files

Files

Keter/App.hs view
@@ -137,35 +137,35 @@     loop (V.toList $ bconfigStanzas bconfig) [] [] Map.empty   where     loop [] wacs backs actions = f wacs backs actions-    loop (StanzaWebApp wac:stanzas) wacs backs actions = bracketOnError+    loop (Stanza (StanzaWebApp wac) rs:stanzas) wacs backs actions = bracketOnError         (getPort (ascLog asc) (ascPortPool asc) >>= either throwIO return)         (releasePort (ascPortPool asc))         (\port -> loop             stanzas             (wac { waconfigPort = port } : wacs)             backs-            (Map.unions $ actions : map (\host -> Map.singleton host $ PAPort port) hosts))+            (Map.unions $ actions : map (\host -> Map.singleton host (PAPort port, rs)) hosts))       where         hosts = Set.toList $ Set.insert (waconfigApprootHost wac) (waconfigHosts wac)-    loop (StanzaStaticFiles sfc:stanzas) wacs backs actions0 =+    loop (Stanza (StanzaStaticFiles sfc) rs:stanzas) wacs backs actions0 =         loop stanzas wacs backs actions       where         actions = Map.unions                 $ actions0-                : map (\host -> Map.singleton host $ PAStatic sfc)+                : map (\host -> Map.singleton host (PAStatic sfc, rs))                   (Set.toList (sfconfigHosts sfc))-    loop (StanzaRedirect red:stanzas) wacs backs actions0 =+    loop (Stanza (StanzaRedirect red) rs:stanzas) wacs backs actions0 =         loop stanzas wacs backs actions       where         actions = Map.unions                 $ actions0-                : map (\host -> Map.singleton host $ PARedirect red)+                : map (\host -> Map.singleton host (PARedirect red, rs))                   (Set.toList (redirconfigHosts red))-    loop (StanzaReverseProxy rev:stanzas) wacs backs actions0 =+    loop (Stanza (StanzaReverseProxy rev) rs:stanzas) wacs backs actions0 =         loop stanzas wacs backs actions       where-        actions = Map.insert (CI.mk $ reversingHost rev) (PAReverseProxy rev) actions0-    loop (StanzaBackground back:stanzas) wacs backs actions =+        actions = Map.insert (CI.mk $ reversingHost rev) (PAReverseProxy rev, rs) actions0+    loop (Stanza (StanzaBackground back) _:stanzas) wacs backs actions =         loop stanzas wacs (back:backs) actions  withRotatingLog :: AppStartConfig@@ -197,8 +197,8 @@     ascLog SanityChecksPassed     f   where-    go (StanzaWebApp WebAppConfig {..}) = isExec waconfigExec-    go (StanzaBackground BackgroundConfig {..}) = isExec bgconfigExec+    go (Stanza (StanzaWebApp WebAppConfig {..}) _) = isExec waconfigExec+    go (Stanza (StanzaBackground BackgroundConfig {..}) _) = isExec bgconfigExec     go _ = return ()      isExec fp = do@@ -273,9 +273,15 @@             if waconfigSsl                 then ("https://", if httpsPort == 443 then "" else ':' : show httpsPort)                 else ("http://",  if httpPort  ==  80 then "" else ':' : show httpPort)-        env = ("PORT", pack $ show waconfigPort)-            : ("APPROOT", scheme <> CI.original waconfigApprootHost <> pack extport)-            : Map.toList waconfigEnvironment ++ otherEnv+        env = Map.toList $ Map.unions+            -- Ordering chosen specifically to precedence rules: app specific,+            -- plugins, global, and then auto-set Keter variables.+            [ waconfigEnvironment+            , Map.fromList otherEnv+            , kconfigEnvironment ascKeterConfig+            , Map.singleton "PORT" $ pack $ show waconfigPort+            , Map.singleton "APPROOT" $ scheme <> CI.original waconfigApprootHost <> pack extport+            ]     exec <- canonicalizePath waconfigExec     bracketOnError         (monitorProcess
Keter/Proxy.hs view
@@ -13,8 +13,9 @@ import qualified Data.ByteString.Char8             as S8 import qualified Data.CaseInsensitive              as CI import           Data.Default-import           Data.Monoid                       (mappend)-import           Data.Text.Encoding                (encodeUtf8)+import           Data.Monoid                       (mappend, mempty)+import           Data.Text.Encoding                (encodeUtf8, decodeUtf8With)+import           Data.Text.Encoding.Error          (lenientDecode) import qualified Data.Vector                       as V import qualified Filesystem.Path.CurrentOS         as F import           Keter.Types@@ -45,26 +46,22 @@ reverseProxy :: Bool              -> Manager -> HostLookup -> ListeningPort -> IO () reverseProxy useHeader manager hostLookup listener =-    run $ gzip def $ withClient useHeader protocol manager hostLookup+    run $ gzip def $ withClient isSecure useHeader manager hostLookup   where     warp host port = Warp.setHost host $ Warp.setPort port Warp.defaultSettings-    run =+    (run, isSecure) =         case listener of-            LPInsecure host port -> Warp.runSettings (warp host port)-            LPSecure host port cert key -> WarpTLS.runTLS+            LPInsecure host port -> (Warp.runSettings (warp host port), False)+            LPSecure host port cert key -> (WarpTLS.runTLS                 (WarpTLS.tlsSettings (F.encodeString cert) (F.encodeString key))-                (warp host port)-    protocol =-        case listener of-            LPInsecure _ _ -> "http"-            LPSecure _ _ _ _ -> "https"+                (warp host port), True) -withClient :: Bool -- ^ use incoming request header for IP address-           -> ByteString -- ^ protocol, for X-Forwarded-Proto+withClient :: Bool -- ^ is secure?+           -> Bool -- ^ use incoming request header for IP address            -> Manager            -> HostLookup            -> Wai.Application-withClient useHeader protocol manager portLookup req0 sendResponse =+withClient isSecure useHeader manager portLookup req0 sendResponse =     timeBound (5 * 60 * 1000 * 1000) (waiProxyToSettings getDest def         { wpsSetIpHeader =             if useHeader@@ -72,6 +69,10 @@                 else SIHFromSocket         } manager req0 sendResponse)   where+    protocol+        | isSecure = "https"+        | otherwise = "http"+     -- FIXME This is a temporary workaround for     -- https://github.com/snoyberg/keter/issues/29. After some research, it     -- seems like Warp is behaving properly here. I'm still not certain why the@@ -97,7 +98,20 @@         mport <- liftIO $ portLookup $ S.takeWhile (/= 58) host         case mport of             Nothing -> return $ WPRResponse $ unknownHostResponse host-            Just action -> performAction req action+            Just (action, requiresSecure)+                | requiresSecure && not isSecure -> performHttpsRedirect host req+                | otherwise -> performAction req action++    performHttpsRedirect host =+        return . WPRResponse . redirectApp config+      where+        host' = CI.mk $ decodeUtf8With lenientDecode host+        config = RedirectConfig+            { redirconfigHosts = mempty+            , redirconfigStatus = 301+            , redirconfigActions = V.singleton $ RedirectAction SPAny+                                 $ RDPrefix True host' Nothing+            }      performAction req (PAPort port) =         return $ WPRModifiedRequest req' $ ProxyDest "127.0.0.1" port
Keter/Types.hs view
@@ -11,7 +11,9 @@     , StaticFilesConfig (..)     , KeterConfig (..)     , Stanza (..)-    , ProxyAction (..)+    , StanzaRaw (..)+    , ProxyAction+    , ProxyActionRaw (..)     , RedirectDest (..)     , RedirectAction (..)     , SourcePath (..)@@ -19,5 +21,6 @@     , AppInput (..)     , BackgroundConfig (..)     , RestartCount (..)+    , RequiresSecure     ) import Network.HTTP.ReverseProxy.Rewrite as X (ReverseProxyConfig (..), RewriteRule (..))
Keter/Types/V10.hs view
@@ -39,9 +39,9 @@     type Previous BundleConfig = V04.BundleConfig     toCurrent (V04.BundleConfig webapp statics redirs) = BundleConfig         { bconfigStanzas = V.concat-            [ maybe V.empty V.singleton $ fmap (StanzaWebApp . toCurrent) webapp-            , V.fromList $ map (StanzaStaticFiles . toCurrent) $ Set.toList statics-            , V.fromList $ map (StanzaRedirect . toCurrent) $ Set.toList redirs+            [ maybe V.empty V.singleton $ fmap (flip Stanza False . StanzaWebApp . toCurrent) webapp+            , V.fromList $ map (flip Stanza False . StanzaStaticFiles . toCurrent) $ Set.toList statics+            , V.fromList $ map (flip Stanza False . StanzaRedirect . toCurrent) $ Set.toList redirs             ]         , bconfigPlugins =             case webapp >>= HashMap.lookup "postgres" . V04.configRaw of@@ -93,6 +93,8 @@     -- ^ External HTTP port when generating APPROOTs.     , kconfigExternalHttpsPort :: !Int     -- ^ External HTTPS port when generating APPROOTs.+    , kconfigEnvironment :: !(Map Text Text)+    -- ^ Environment variables to be passed to all apps.     }  instance ToCurrent KeterConfig where@@ -102,10 +104,11 @@         , kconfigPortPool = portman         , kconfigListeners = NonEmptyVector (LPInsecure host port) (getSSL ssl)         , kconfigSetuid = setuid-        , kconfigBuiltinStanzas = V.fromList $ map StanzaReverseProxy $ Set.toList rproxy+        , kconfigBuiltinStanzas = V.fromList $ map (flip Stanza False . StanzaReverseProxy) $ Set.toList rproxy         , kconfigIpFromHeader = ipFromHeader         , kconfigExternalHttpPort = 80         , kconfigExternalHttpsPort = 443+        , kconfigEnvironment = Map.empty         }       where         getSSL Nothing = V.empty@@ -125,6 +128,7 @@         , kconfigIpFromHeader = False         , kconfigExternalHttpPort = 80         , kconfigExternalHttpsPort = 443+        , kconfigEnvironment = Map.empty         }  instance ParseYamlFile KeterConfig where@@ -143,8 +147,14 @@             <*> o .:? "ip-from-header" .!= False             <*> o .:? "external-http-port" .!= 80             <*> o .:? "external-https-port" .!= 443+            <*> o .:? "env" .!= Map.empty -data Stanza port+-- | Whether we should force redirect to HTTPS routes.+type RequiresSecure = Bool++data Stanza port = Stanza (StanzaRaw port) RequiresSecure++data StanzaRaw port     = StanzaStaticFiles !StaticFilesConfig     | StanzaRedirect !RedirectConfig     | StanzaWebApp !(WebAppConfig port)@@ -160,24 +170,38 @@ -- 1. Webapps will be assigned ports. -- -- 2. Not all stanzas have an associated proxy action.-data ProxyAction = PAPort Port-                 | PAStatic StaticFilesConfig-                 | PARedirect RedirectConfig-                 | PAReverseProxy ReverseProxyConfig+data ProxyActionRaw+    = PAPort Port+    | PAStatic StaticFilesConfig+    | PARedirect RedirectConfig+    | PAReverseProxy ReverseProxyConfig     deriving Show +type ProxyAction = (ProxyActionRaw, RequiresSecure)+ instance ParseYamlFile (Stanza ()) where     parseYamlFile basedir = withObject "Stanza" $ \o -> do         typ <- o .: "type"-        case typ of+        needsHttps <- o .:? "requires-secure" .!= False+        raw <- case typ of             "static-files" -> fmap StanzaStaticFiles $ parseYamlFile basedir $ Object o             "redirect" -> fmap StanzaRedirect $ parseYamlFile basedir $ Object o             "webapp" -> fmap StanzaWebApp $ parseYamlFile basedir $ Object o             "reverse-proxy" -> fmap StanzaReverseProxy $ parseJSON $ Object o             "background" -> fmap StanzaBackground $ parseYamlFile basedir $ Object o             _ -> fail $ "Unknown stanza type: " ++ typ+        return $ Stanza raw needsHttps  instance ToJSON (Stanza ()) where+    toJSON (Stanza raw rs) = addRequiresSecure rs raw++addRequiresSecure :: ToJSON a => Bool -> a -> Value+addRequiresSecure rs x =+    case toJSON x of+        Object o -> Object $ HashMap.insert "requires-secure" (toJSON rs) o+        v -> v++instance ToJSON (StanzaRaw ()) where     toJSON (StanzaStaticFiles x) = addStanzaType "static-files" x     toJSON (StanzaRedirect x) = addStanzaType "redirect" x     toJSON (StanzaWebApp x) = addStanzaType "webapp" x
+ changelog.md view
@@ -0,0 +1,21 @@+__1.3.5__ All stanzas may have the `requires-secure` property to force redirect to HTTPS. You can set additional environment variables in your global Keter config file.++__1.3.4__ Support for overriding external ports. Support for keter.yml in addition to keter.yaml. Case insensitive hostname lookups.++__1.3.3__ Set the X-Forwarded-Proto header++__1.3.2__ Enable GZIP middleware++__1.3.1__ Upgrade to WAI 3.0++__1.3.0__ Upgrade to conduit 1.1++__1.0.1__ Permit use of wildcard subdomains and exceptions to wildcards. Convert internal strings to use Data.Text in more places. (Although internationalized domain names are not supported unless entered in punycode in configuration files.)++__1.0.0__ Significant overhaul. We now support monitoring of much more arbitrary jobs (e.g., background tasks), have a proper plugin system (PostgreSQL is no longer a required component), and have a much better system for tracking hostname mapping changes.++__0.4.0__ Switch to fsnotify to get cross-platform support. No longer using raw proxies, but instead WAI proxies.++__0.3.7__ Sending a HUP signal reloads the list of deployed apps. This is useful for circumstances where inotify does not work correctly, such as on file systems which do not support it.++__0.3.5__ You can now create Keter bundles without any applications. These can contain static hosts and redirects.
keter.cabal view
@@ -1,30 +1,8 @@ Name:                keter-Version:             1.3.4+Version:             1.3.5 Synopsis:            Web application deployment manager, focusing on Haskell web frameworks Description:     Handles deployment of web apps, providing a reverse proxy to achieve zero downtime deployments. For more information, please see the README on Github: <https://github.com/snoyberg/keter#readme>-    .-    Release history:-    .-    [1.3.4] Support for overriding external ports. Support for keter.yml in addition to keter.yaml. Case insensitive hostname lookups.-    .-    [1.3.3] Set the X-Forwarded-Proto header-    .-    [1.3.2] Enable GZIP middleware-    .-    [1.3.1] Upgrade to WAI 3.0-    .-    [1.3.0] Upgrade to conduit 1.1-    .-    [1.0.1] Permit use of wildcard subdomains and exceptions to wildcards. Convert internal strings to use Data.Text in more places. (Although internationalized domain names are not supported unless entered in punycode in configuration files.)-    .-    [1.0.0] Significant overhaul. We now support monitoring of much more arbitrary jobs (e.g., background tasks), have a proper plugin system (PostgreSQL is no longer a required component), and have a much better system for tracking hostname mapping changes.-    .-    [0.4.0] Switch to fsnotify to get cross-platform support. No longer using raw proxies, but instead WAI proxies.-    .-    [0.3.7] Sending a HUP signal reloads the list of deployed apps. This is useful for circumstances where inotify does not work correctly, such as on file systems which do not support it.-    .-    [0.3.5] You can now create Keter bundles without any applications. These can contain static hosts and redirects. Homepage:            http://www.yesodweb.com/ License:             MIT License-file:        LICENSE@@ -33,6 +11,7 @@ Category:            Web, Yesod Build-type:          Simple Cabal-version:       >=1.8+extra-source-files:  changelog.md  --Data-Files:        incoming/foo/bundle.sh, incoming/foo/config/keter.yaml