Skip to content

Commit 10ea926

Browse files
committed
Use ADTs instead of Either String in GCP Auth code
1 parent 3f1ee81 commit 10ea926

File tree

1 file changed

+49
-32
lines changed
  • kubernetes-client/src/Kubernetes/Client/Auth

1 file changed

+49
-32
lines changed

kubernetes-client/src/Kubernetes/Client/Auth/GCP.hs

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ data GCPAuth = GCPAuth { gcpAccessToken :: TVar(Maybe Text)
3939
instance AuthMethod GCPAuth where
4040
applyAuthMethod _ gcp req = do
4141
token <- getToken gcp
42-
>>= either (throwM . GCPGetTokenException) pure
42+
>>= either throwM pure
4343
pure
4444
$ setHeader req [("Authorization", "Bearer " <> (Text.encodeUtf8 token))]
4545
& L.set rAuthTypesL []
@@ -50,19 +50,25 @@ gcpAuth AuthInfo{authProvider = Just(AuthProviderConfig "gcp" (Just cfg))} (tls,
5050
= Just $ do
5151
configOrErr <- parseGCPAuthInfo cfg
5252
case configOrErr of
53-
Left e -> throwM $ GCPAuthParsingException e
53+
Left e -> throwM e
5454
Right gcp -> pure (tls, addAuthMethod kubecfg gcp)
5555
gcpAuth _ _ = Nothing
5656

57-
data GCPAuthParsingException = GCPAuthParsingException String
57+
data GCPAuthParsingException = GCPAuthMissingInformation String
58+
| GCPAuthInvalidExpiry String
59+
| GCPAuthInvalidTokenJSONPath String
60+
| GCPAuthInvalidExpiryJSONPath String
5861
deriving Show
5962
instance Exception GCPAuthParsingException
6063

61-
data GCPGetTokenException = GCPGetTokenException String
64+
data GCPGetTokenException = GCPCmdProducedInvalidJSON String
65+
| GCPTokenNotFound String
66+
| GCPTokenExpiryNotFound String
67+
| GCPTokenExpiryInvalid String
6268
deriving Show
6369
instance Exception GCPGetTokenException
6470

65-
getToken :: GCPAuth -> IO (Either String Text)
71+
getToken :: GCPAuth -> IO (Either GCPGetTokenException Text)
6672
getToken g@(GCPAuth{..}) = getCurrentToken g
6773
>>= maybe (fetchToken g) (return . Right)
6874

@@ -77,38 +83,49 @@ getCurrentToken (GCPAuth{..}) = do
7783
then maybeToken
7884
else Nothing
7985

80-
-- TODO: log if parsed expiry is invalid
81-
fetchToken :: GCPAuth -> IO (Either String Text)
86+
fetchToken :: GCPAuth -> IO (Either GCPGetTokenException Text)
8287
fetchToken GCPAuth{..} = do
8388
(stdOut, _) <- readProcess_ gcpCmd
84-
let credsJSON = Aeson.eitherDecode stdOut
85-
token = runJSONPath gcpTokenKey =<< credsJSON
86-
expText = runJSONPath gcpExpiryKey =<< credsJSON
87-
expiry :: Either String (Maybe UTCTime)
88-
expiry = Just <$> (parseExpiryTime =<< expText)
89-
atomically $ do
90-
writeTVar gcpAccessToken (rightToMaybe token)
91-
writeTVar gcpTokenExpiry (either (const Nothing) id expiry)
92-
return token
89+
case parseTokenAndExpiry stdOut of
90+
Right (token, expiry) -> do
91+
atomically $ do
92+
writeTVar gcpAccessToken (Just token)
93+
writeTVar gcpTokenExpiry (Just expiry)
94+
return $ Right token
95+
Left x -> return $ Left x
96+
where
97+
parseTokenAndExpiry credsStr = do
98+
credsJSON <- Aeson.eitherDecode credsStr
99+
& mapLeft GCPCmdProducedInvalidJSON
100+
token <- runJSONPath gcpTokenKey credsJSON
101+
& mapLeft GCPTokenNotFound
102+
expText <- runJSONPath gcpExpiryKey credsJSON
103+
& mapLeft GCPTokenExpiryNotFound
104+
expiry <- parseExpiryTime expText
105+
& mapLeft GCPTokenExpiryInvalid
106+
return (token, expiry)
93107

94-
parseGCPAuthInfo :: Map Text Text -> IO (Either String GCPAuth)
108+
parseGCPAuthInfo :: Map Text Text -> IO (Either GCPAuthParsingException GCPAuth)
95109
parseGCPAuthInfo m = do
96110
gcpAccessToken <- atomically $ newTVar $ Map.lookup "access-token" m
97-
case maybe (pure Nothing) ((Just <$>) . parseExpiryTime) $ Map.lookup "expiry" m of
98-
(Left e) -> return $ Left e
99-
Right t -> do
100-
gcpTokenExpiry <- atomically $ newTVar t
101-
return $ do
102-
cmdPath <- Text.unpack <$> lookupEither m "cmd-path"
103-
cmdArgs <- Text.splitOn " " <$> lookupEither m "cmd-args"
104-
gcpTokenKey <- readJSONPath m "token-key" [JSONPath [KeyChild "token_expiry"]]
105-
gcpExpiryKey <- readJSONPath m "expiry-key" [JSONPath [KeyChild "access_token"]]
106-
let gcpCmd = proc cmdPath (map Text.unpack cmdArgs)
107-
pure $ GCPAuth{..}
108-
109-
lookupEither :: (Show key, Ord key) => Map key val -> key -> Either String val
110-
lookupEither m k = maybeToRight e $ Map.lookup k m
111-
where e = "Couldn't find key: " <> show k <> " in GCP auth info"
111+
eitherGCPExpiryToken <- sequence $ fmap (atomically . newTVar) lookupAndParseExpiry
112+
return $ do
113+
gcpTokenExpiry <- mapLeft GCPAuthInvalidExpiry eitherGCPExpiryToken
114+
cmdPath <- Text.unpack <$> lookupEither "cmd-path"
115+
cmdArgs <- Text.splitOn " " <$> lookupEither "cmd-args"
116+
gcpTokenKey <- readJSONPath m "token-key" [JSONPath [KeyChild "token_expiry"]]
117+
& mapLeft GCPAuthInvalidTokenJSONPath
118+
gcpExpiryKey <- readJSONPath m "expiry-key" [JSONPath [KeyChild "access_token"]]
119+
& mapLeft GCPAuthInvalidExpiryJSONPath
120+
let gcpCmd = proc cmdPath (map Text.unpack cmdArgs)
121+
pure $ GCPAuth{..}
122+
where
123+
lookupAndParseExpiry =
124+
case Map.lookup "expiry" m of
125+
Nothing -> Right Nothing
126+
Just expiryText -> Just <$> parseExpiryTime expiryText
127+
lookupEither key = Map.lookup key m
128+
& maybeToRight (GCPAuthMissingInformation $ Text.unpack key)
112129

113130
parseExpiryTime :: Text -> Either String UTCTime
114131
parseExpiryTime s = zonedTimeToUTC <$> parseTimeRFC3339 s

0 commit comments

Comments
 (0)