{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeApplications #-}

{-|
Helper module for working with @kubectl@ processes.
-}

module Test.Sandwich.Contexts.Kubernetes.Kubectl (
  -- * Run commands with kubectl
  askKubectlArgs
  , askKubectlEnvironment
  , getKubectlEnvironment
  ) where

import Control.Monad.Logger
import qualified Data.List as L
import Relude
import Test.Sandwich
import Test.Sandwich.Contexts.Files
import Test.Sandwich.Contexts.Kubernetes.Types
import UnliftIO.Environment


-- | Retrieve the @kubectl@ binary path and the set of environment variables to use when invoking it.
-- Derives these from a 'HasFile' context and the 'KubernetesClusterContext' respectively.
--
-- Useful for running Kubectl commands with 'System.Process.createProcess' etc.
askKubectlArgs :: (
  KubectlBasic context m
  )
  -- | Returns the @kubectl@ binary and environment variables.
  => m (FilePath, [(String, String)])
askKubectlArgs :: forall context (m :: * -> *).
KubectlBasic context m =>
m (FilePath, [(FilePath, FilePath)])
askKubectlArgs = do
  kubectlBinary <- forall (a :: Symbol) context (m :: * -> *).
(MonadReader context m, HasFile context a) =>
m FilePath
askFile @"kubectl"
  (kubectlBinary, ) <$> askKubectlEnvironment

-- | Same as 'askKubectlArgs', but only returns the environment variables.
askKubectlEnvironment :: (
  KubernetesClusterBasic context m
  )
  -- | Returns the @kubectl@ environment variables.
  => m [(String, String)]
askKubectlEnvironment :: forall context (m :: * -> *).
KubernetesClusterBasic context m =>
m [(FilePath, FilePath)]
askKubectlEnvironment = do
  KubernetesClusterContext {..} <- Label "kubernetesCluster" KubernetesClusterContext
-> m KubernetesClusterContext
forall context (l :: Symbol) a (m :: * -> *).
(HasLabel context l a, MonadReader context m) =>
Label l a -> m a
getContext Label "kubernetesCluster" KubernetesClusterContext
kubernetesCluster
  baseEnv <- getEnvironment
  return $ L.nubBy (\(FilePath, FilePath)
x (FilePath, FilePath)
y -> (FilePath, FilePath) -> FilePath
forall a b. (a, b) -> a
fst (FilePath, FilePath)
x FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== (FilePath, FilePath) -> FilePath
forall a b. (a, b) -> a
fst (FilePath, FilePath)
y) (("KUBECONFIG", kubernetesClusterKubeConfigPath) : baseEnv)

-- | Same as 'askKubectlArgs', but only returns the environment variables.
getKubectlEnvironment :: (
  MonadLoggerIO m
  )
  -- | Kubernetes cluster context
  => KubernetesClusterContext
  -- | Returns the @kubectl@ environment variables.
  -> m [(String, String)]
getKubectlEnvironment :: forall (m :: * -> *).
MonadLoggerIO m =>
KubernetesClusterContext -> m [(FilePath, FilePath)]
getKubectlEnvironment (KubernetesClusterContext {Int
FilePath
(Manager, KubernetesClientConfig)
Text
KubernetesClusterType
kubernetesClusterType :: KubernetesClusterContext -> KubernetesClusterType
kubernetesClusterClientConfig :: KubernetesClusterContext -> (Manager, KubernetesClientConfig)
kubernetesClusterNumNodes :: KubernetesClusterContext -> Int
kubernetesClusterKubeConfigPath :: KubernetesClusterContext -> FilePath
kubernetesClusterName :: KubernetesClusterContext -> Text
kubernetesClusterName :: Text
kubernetesClusterKubeConfigPath :: FilePath
kubernetesClusterNumNodes :: Int
kubernetesClusterClientConfig :: (Manager, KubernetesClientConfig)
kubernetesClusterType :: KubernetesClusterType
..}) = do
  baseEnv <- m [(FilePath, FilePath)]
forall (m :: * -> *). MonadIO m => m [(FilePath, FilePath)]
getEnvironment
  return $ L.nubBy (\(FilePath, FilePath)
x (FilePath, FilePath)
y -> (FilePath, FilePath) -> FilePath
forall a b. (a, b) -> a
fst (FilePath, FilePath)
x FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== (FilePath, FilePath) -> FilePath
forall a b. (a, b) -> a
fst (FilePath, FilePath)
y) (("KUBECONFIG", kubernetesClusterKubeConfigPath) : baseEnv)