Skip to content

Commit

Permalink
Merge pull request #283 from zoominsoftware/feat/healthcheck-endpoint
Browse files Browse the repository at this point in the history
Add config "healthcheck-path" to respond 200 on
  • Loading branch information
jappeace authored Nov 10, 2023
2 parents cbac18c + 3e6f209 commit 7c7202d
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 3 deletions.
2 changes: 2 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## 2.1.3

* Add `healthcheck-path` global config for Keter-only healthchecks. PR #283

* Fix config keys `unknown-host-response-file` and `missing-host-response-file`
accidentally flipped. PR #282
* In case reading any one of `*-host-response-file` fails, keter now logs a warning,
Expand Down
5 changes: 3 additions & 2 deletions etc/keter-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ listeners:
session: true

# User to run applications as

# setuid: ubuntu

# Get the user's IP address from x-forwarded-for. Useful when sitting behind a
# load balancer like Amazon ELB.

# ip-from-header: true

# If set, this path will respond 200 OK to requests on any vhost
# healthcheck-path: /keter-health

# Control the port numbers assigned via APPROOT
# external-http-port: 8080
# external-https-port: 450
Expand Down
1 change: 1 addition & 0 deletions keter.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ library
Keter.Yaml.FilePath

other-modules: Keter.Aeson.KeyHelper
Paths_keter
ghc-options: -Wall
c-sources: cbits/process-tracker.c
hs-source-dirs: src
Expand Down
6 changes: 5 additions & 1 deletion src/Keter/Config/V10.hs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ data KeterConfig = KeterConfig
, kconfigProxyException :: !(Maybe F.FilePath)

, kconfigRotateLogs :: !Bool
, kconfigHealthcheckPath :: !(Maybe Text)
}

instance ToCurrent KeterConfig where
Expand All @@ -134,6 +135,7 @@ instance ToCurrent KeterConfig where
, kconfigMissingHostResponse = Nothing
, kconfigProxyException = Nothing
, kconfigRotateLogs = True
, kconfigHealthcheckPath = Nothing
}
where
getSSL Nothing = V.empty
Expand Down Expand Up @@ -162,6 +164,7 @@ defaultKeterConfig = KeterConfig
, kconfigMissingHostResponse = Nothing
, kconfigProxyException = Nothing
, kconfigRotateLogs = True
, kconfigHealthcheckPath = Nothing
}

instance ParseYamlFile KeterConfig where
Expand All @@ -187,6 +190,7 @@ instance ParseYamlFile KeterConfig where
<*> o .:? "missing-host-response-file"
<*> o .:? "proxy-exception-response-file"
<*> o .:? "rotate-logs" .!= True
<*> o .:? "app-crash-hook"

-- | Whether we should force redirect to HTTPS routes.
type RequiresSecure = Bool
Expand Down Expand Up @@ -317,7 +321,7 @@ instance ToCurrent RedirectConfig where

instance ParseYamlFile RedirectConfig where
parseYamlFile _ = withObject "RedirectConfig" $ \o -> RedirectConfig
<$> (Set.map CI.mk <$> ((o .: "hosts" <|> (Set.singleton <$> (o .: "host")))))
<$> (Set.map CI.mk <$> (o .: "hosts" <|> Set.singleton <$> o .: "host"))
<*> o .:? "status" .!= 303
<*> o .: "actions"
<*> o .:? "ssl" .!= SSLFalse
Expand Down
17 changes: 17 additions & 0 deletions src/Keter/Proxy.hs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import System.FilePath (FilePath)
import Control.Monad.Logger
import Control.Exception (SomeException)
import Network.HTTP.Types (mkStatus,
status200,
status301, status302,
status303, status307,
status404, status502)
Expand All @@ -76,6 +77,9 @@ import qualified Network.TLS as TLS
import qualified System.Directory as Dir
import Keter.Context

import Data.Version (showVersion)
import qualified Paths_keter as Pkg

#if !MIN_VERSION_http_reverse_proxy(0,6,0)
defaultWaiProxySettings = def
#endif
Expand All @@ -91,6 +95,7 @@ data ProxySettings = MkProxySettings
, psManager :: !Manager
, psIpFromHeader :: Bool
, psConnectionTimeBound :: Int
, psHealthcheckPath :: !(Maybe ByteString)
, psUnknownHost :: ByteString -> ByteString
, psMissingHost :: ByteString
, psProxyException :: ByteString
Expand All @@ -107,6 +112,7 @@ makeSettings hostman = do
-- configuration option is in milliseconds
let psConnectionTimeBound = kconfigConnectionTimeBound * 1000
let psIpFromHeader = kconfigIpFromHeader
let psHealthcheckPath = encodeUtf8 <$> kconfigHealthcheckPath
pure $ MkProxySettings{..}
where
psHostLookup = HostMan.lookupAction hostman . CI.mk
Expand Down Expand Up @@ -178,6 +184,10 @@ withClient isSecure = do


getDest :: ProxySettings -> Wai.Request -> IO (LocalWaiProxySettings, WaiProxyResponse)
-- respond to healthckecks, regardless of Host header value and presence
getDest MkProxySettings{..} req | psHealthcheckPath == Just (Wai.rawPathInfo req)
= return (defaultLocalWaiProxySettings, WPRResponse healthcheckResponse)
-- inspect Host header to determine which App to proxy to
getDest cfg@MkProxySettings{..} req =
case Wai.requestHeaderHost req of
Nothing -> do
Expand Down Expand Up @@ -303,6 +313,13 @@ handleProxyException handleException onexceptBody except req respond = do
handleException req except
respond $ missingHostResponse onexceptBody

healthcheckResponse :: Wai.Response
healthcheckResponse = Wai.responseBuilder
status200
[("Content-Type", "text/plain; charset=utf-8")]
$ "Keter " <> (copyByteString . S8.pack . showVersion) Pkg.version
<> " is doing okay!\n"

defaultProxyException :: ByteString
defaultProxyException = "<!DOCTYPE html>\n<html><head><title>Welcome to Keter</title></head><body><h1>Welcome to Keter</h1><p>There was a proxy error, check the keter logs for details.</p></body></html>"

Expand Down
1 change: 1 addition & 0 deletions test/Spec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,5 @@ headThenPostNoCrash = do
, psProxyException = ""
, psIpFromHeader = False
, psConnectionTimeBound = 5 * 60 * 1000
, psHealthcheckPath = Nothing
}

0 comments on commit 7c7202d

Please sign in to comment.