Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/Stackctl/AWS/Core.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module Stackctl.AWS.Core
, withAssumedRole

-- * Error-handling
, handlingAuthError
, handlingServiceError
, formatServiceError

Expand All @@ -38,6 +39,7 @@ import Amazonka
, serviceError_code
, serviceError_message
, serviceError_requestId
, _AuthError
, _Sensitive
, _ServiceError
)
Expand All @@ -49,6 +51,7 @@ import qualified Amazonka.Env as Amazonka
import Amazonka.STS.AssumeRole
import Control.Monad.AWS
import Control.Monad.Logger (defaultLoc, toLogStr)
import qualified Data.Text as T
import Data.Typeable (typeRep)
import Stackctl.AWS.Orphans ()
import UnliftIO.Exception.Lens (handling)
Expand Down Expand Up @@ -149,6 +152,22 @@ newtype AccountId = AccountId
}
deriving newtype (Eq, Ord, Show, ToJSON)

-- | Handle 'AuthError', log it and 'exitFailure'
handlingAuthError :: (MonadUnliftIO m, MonadLogger m) => m a -> m a
handlingAuthError =
handling _AuthError $ \e -> do
logError $ msg :# ["exception" .= displayException e]
exitFailure
where
msg =
"No AWS credentials were found in your environment."
<> continuation "For details of where stackctl looks for credentials, see:"
<> continuation
"https://hackage.haskell.org/package/amazonka-2.0/docs/Amazonka-Auth.html#v:discover"

-- Shift the continuation lines to line up with the first message line
continuation x = "\n" <> T.replicate 32 " " <> x

-- | Handle 'ServiceError', log it and 'exitFailure'
--
-- This is useful at the top-level of the app, where we'd be crashing anyway. It
Expand Down
10 changes: 7 additions & 3 deletions src/Stackctl/CLI.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Control.Monad.AWS as AWS
import Control.Monad.AWS.ViaReader as AWS
import Control.Monad.Catch (MonadCatch)
import Control.Monad.Trans.Resource (MonadResource, ResourceT, runResourceT)
import Stackctl.AWS.Core (handlingAuthError)
import qualified Stackctl.AWS.Core as AWS
import Stackctl.AWS.Scope
import Stackctl.AutoSSO
Expand Down Expand Up @@ -103,9 +104,12 @@ runAppT options f = do
envLogSettings

withLogger logSettings $ \appLogger -> do
appAwsEnv <- runWithLogger appLogger $ handleAutoSSO options $ do
logDebug "Discovering AWS credentials"
AWS.discover
appAwsEnv <- runWithLogger appLogger
$ handleAutoSSO options
$ handlingAuthError
$ do
logDebug "Discovering AWS credentials"
AWS.discover
appConfig <- runWithLogger appLogger loadConfigOrExit
appAwsScope <- AWS.runEnvT fetchAwsScope appAwsEnv

Expand Down