packages feed

instana-haskell-trace-sdk-0.10.0.0: test/agent-stub/Instana/SDK/AgentStub/Config.hs

{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE OverloadedStrings #-}
module Instana.SDK.AgentStub.Config
  ( AgentStubConfig(..)
  , readConfig
  ) where


import           Data.Maybe                              (fromMaybe)
import           Data.String                             (fromString)
import           Data.Text                               (Text)
import qualified Data.Text                               as T
import           GHC.Generics
import           Instana.SDK.AgentStub.DiscoveryResponse (SecretsConfig (SecretsConfig))
import qualified Instana.SDK.AgentStub.DiscoveryResponse as DiscoveryResponse
import qualified Network.Wai.Handler.Warp                as Warp
import           System.Environment                      (lookupEnv)
import           Text.Read                               (readMaybe)



data AgentStubConfig = AgentStubConfig
  { bindHost                     :: Warp.HostPreference
  , bindPort                     :: Int
  , secretsConfig                :: SecretsConfig
  , extraHeadersViaTracingConfig :: [Text]
  , extraHeadersViaLegacyConfig  :: [Text]
  , startupDelay                 :: Int
  , simulateConnectionLoss       :: Bool
  , simulatPidTranslation        :: Bool
  } deriving (Eq, Show, Generic)


defaultSecretsConfig :: SecretsConfig
defaultSecretsConfig =
  SecretsConfig
    { DiscoveryResponse.matcher = "contains-ignore-case"
    , DiscoveryResponse.list = ["key", "pass", "secret"]
    }


readConfig :: IO AgentStubConfig
readConfig = do
  -- Since the stub is only used locally, binding to host "127.0.0.1" is safer
  -- and also more convenient than binding to something like "*4"
  -- (see https://hackage.haskell.org/package/warp-3.2.9/docs/Network-Wai-Handler-Warp.html#t:HostPreference),
  -- as it prevents the MacOS firewall from asking if it is okay to accept
  -- incoming connections every time the app is recompiled and restarted.
  hostString          <- lookupEnvWithDefault    "HOST" "127.0.0.1"
  port                <- lookupEnvIntWithDefault "PORT" 1302
  secrets             <- parseSecretsConfig
  extraHeadersTracing <- parseExtraHeadersConfig "EXTRA_HEADERS_VIA_TRACING_CONFIG"
  extraHeadersLegacy  <- parseExtraHeadersConfig "EXTRA_HEADERS_VIA_LEGACY_CONFIG"
  delay               <- lookupEnvIntWithDefault "STARTUP_DELAY" 0
  connectionLoss      <- lookupFlag              "SIMULATE_CONNECTION_LOSS"
  pidTranslation      <- lookupFlag              "SIMULATE_PID_TRANSLATION"
  let
    hostPreference :: Warp.HostPreference
    hostPreference = fromString hostString
  return
    AgentStubConfig
      { bindHost                     = hostPreference
      , bindPort                     = port
      , secretsConfig                = secrets
      , extraHeadersViaTracingConfig = extraHeadersTracing
      , extraHeadersViaLegacyConfig  = extraHeadersLegacy
      , startupDelay                 = delay
      , simulateConnectionLoss       = connectionLoss
      , simulatPidTranslation        = pidTranslation
      }


lookupEnvWithDefault :: String -> String -> IO String
lookupEnvWithDefault key defaultValue = do
  maybeValue <- lookupEnv key
  return $ fromMaybe defaultValue maybeValue


lookupEnvIntWithDefault :: String -> Int -> IO Int
lookupEnvIntWithDefault key defaultValue = do
  maybeValue <- lookupEnv key
  case maybeValue of
    Just string -> do
      let
        parsed :: Maybe Int
        parsed = readMaybe string
      case parsed of
        Just integer ->
          return integer
        Nothing -> do
          _ <- error
            ("Error: You provided the string \"" ++ string ++
             "\" as the value for configuration option " ++ key ++
             " but this option requires an integer value and I could" ++
             " not convert \"" ++ string ++ "\" to an integer.")
          return defaultValue
    Nothing ->
      return defaultValue


lookupFlag :: String -> IO Bool
lookupFlag key = do
  maybeValue <- lookupEnv key
  return $ case maybeValue of
             Just _ -> True
             _      -> False


parseSecretsConfig :: IO SecretsConfig
parseSecretsConfig = do
  maybeSecretsConfigString <- lookupEnv "SECRETS_CONFIG"
  case maybeSecretsConfigString of
    Just secretsString -> do
      let
        matcherAndList = T.splitOn ":" (T.pack secretsString)
        matcher = head matcherAndList
        listAsString = head $ tail matcherAndList
        list = T.splitOn "," listAsString
      return SecretsConfig
        { DiscoveryResponse.matcher = matcher
        , DiscoveryResponse.list = list
        }
    Nothing -> do
      return defaultSecretsConfig


parseExtraHeadersConfig :: String -> IO [Text]
parseExtraHeadersConfig key = do
  maybeExtraHeadersConfigString <- lookupEnv key
  case maybeExtraHeadersConfigString of
    Just extraHeadersString -> do
      return $ T.splitOn "," (T.pack extraHeadersString)
    Nothing -> do
      return []