{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
{-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns #-}

{-|

Install [Kata Containers](https://katacontainers.io) on a Kubernetes cluster.

-}

module Test.Sandwich.Contexts.Kubernetes.KataContainers (
  -- * Introduce Kata Containers
  introduceKataContainers

  -- * Bracket-style versions
  , withKataContainers
  , withKataContainers'

  -- * Types
  , KataContainersOptions(..)
  , SourceCheckout(..)
  , defaultKataContainersOptions

  , kataContainers
  , KataContainersContext(..)
  , HasKataContainersContext
  ) where

import Control.Lens
import Control.Monad
import Control.Monad.IO.Unlift
import Data.Aeson (FromJSON)
import Data.String.Interpolate
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Data.Yaml as Yaml
import Kubernetes.OpenAPI.Model as Kubernetes
import Kubernetes.OpenAPI.ModelLens as Kubernetes
import Relude hiding (withFile)
import Safe
import System.Exit
import System.FilePath
import Test.Sandwich
import Test.Sandwich.Contexts.Files
import Test.Sandwich.Contexts.Kubernetes.FindImages
import Test.Sandwich.Contexts.Kubernetes.Images
import Test.Sandwich.Contexts.Kubernetes.Kubectl
import Test.Sandwich.Contexts.Kubernetes.Types
import Test.Sandwich.Contexts.Nix
import Test.Sandwich.Waits
import UnliftIO.Process


data KataContainersContext = KataContainersContext {
  KataContainersContext -> KataContainersOptions
kataContainersOptions :: KataContainersOptions
  } deriving (Int -> KataContainersContext -> ShowS
[KataContainersContext] -> ShowS
KataContainersContext -> String
(Int -> KataContainersContext -> ShowS)
-> (KataContainersContext -> String)
-> ([KataContainersContext] -> ShowS)
-> Show KataContainersContext
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> KataContainersContext -> ShowS
showsPrec :: Int -> KataContainersContext -> ShowS
$cshow :: KataContainersContext -> String
show :: KataContainersContext -> String
$cshowList :: [KataContainersContext] -> ShowS
showList :: [KataContainersContext] -> ShowS
Show)

data SourceCheckout =
  SourceCheckoutFilePath FilePath
  | SourceCheckoutNixDerivation Text
  deriving (Int -> SourceCheckout -> ShowS
[SourceCheckout] -> ShowS
SourceCheckout -> String
(Int -> SourceCheckout -> ShowS)
-> (SourceCheckout -> String)
-> ([SourceCheckout] -> ShowS)
-> Show SourceCheckout
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SourceCheckout -> ShowS
showsPrec :: Int -> SourceCheckout -> ShowS
$cshow :: SourceCheckout -> String
show :: SourceCheckout -> String
$cshowList :: [SourceCheckout] -> ShowS
showList :: [SourceCheckout] -> ShowS
Show, SourceCheckout -> SourceCheckout -> Bool
(SourceCheckout -> SourceCheckout -> Bool)
-> (SourceCheckout -> SourceCheckout -> Bool) -> Eq SourceCheckout
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SourceCheckout -> SourceCheckout -> Bool
== :: SourceCheckout -> SourceCheckout -> Bool
$c/= :: SourceCheckout -> SourceCheckout -> Bool
/= :: SourceCheckout -> SourceCheckout -> Bool
Eq)

data KataContainersOptions = KataContainersOptions {
  KataContainersOptions -> SourceCheckout
kataContainersSourceCheckout :: SourceCheckout
  -- | If set, this will overwrite the image in the DaemonSet in @kata-deploy.yaml@ and will set the 'ImagePullPolicy'
  -- to 'IfNotPresent'.
  -- This is useful because it's currently (8\/15\/2024) set to @quay.io\/kata-containers\/kata-deploy:latest@,
  -- with @imagePullPolicy: Always@. This is not reproducible and also doesn't allow us to cache images.
  , KataContainersOptions -> Maybe Text
kataContainersKataDeployImage :: Maybe Text
  -- | Whether to pull the image using Docker and load it onto the cluster using 'loadImageIfNecessary''.
  , KataContainersOptions -> Bool
kataContainersPreloadImages :: Bool
  -- | Whether to label the node(s) with @katacontainers.io/kata-runtime=true@, since this seems not to happen
  -- automatically with kata-deploy.
  , KataContainersOptions -> Bool
kataContainersLabelNode :: Bool
  } deriving (Int -> KataContainersOptions -> ShowS
[KataContainersOptions] -> ShowS
KataContainersOptions -> String
(Int -> KataContainersOptions -> ShowS)
-> (KataContainersOptions -> String)
-> ([KataContainersOptions] -> ShowS)
-> Show KataContainersOptions
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> KataContainersOptions -> ShowS
showsPrec :: Int -> KataContainersOptions -> ShowS
$cshow :: KataContainersOptions -> String
show :: KataContainersOptions -> String
$cshowList :: [KataContainersOptions] -> ShowS
showList :: [KataContainersOptions] -> ShowS
Show)
defaultKataContainersOptions :: KataContainersOptions
defaultKataContainersOptions :: KataContainersOptions
defaultKataContainersOptions = KataContainersOptions {
  kataContainersSourceCheckout :: SourceCheckout
kataContainersSourceCheckout = Text -> SourceCheckout
SourceCheckoutNixDerivation Text
kataContainersDerivation
  , kataContainersKataDeployImage :: Maybe Text
kataContainersKataDeployImage = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
kataContainersDeployImage
  , kataContainersPreloadImages :: Bool
kataContainersPreloadImages = Bool
True
  , kataContainersLabelNode :: Bool
kataContainersLabelNode = Bool
True
  }

kataContainers :: Label "kataContainers" KataContainersContext
kataContainers :: Label "kataContainers" KataContainersContext
kataContainers = Label "kataContainers" KataContainersContext
forall {k} (l :: Symbol) (a :: k). Label l a
Label
type HasKataContainersContext context = HasLabel context "kataContainers" KataContainersContext

type ContextWithKataContainers context =
  LabelValue "kataContainers" KataContainersContext
  :> LabelValue "file-kubectl" (EnvironmentFile "kubectl")
  :> context

-- | Install Kata Containers on the cluster and introduce a 'KataContainersContext'.
introduceKataContainers :: (
  Typeable context, KubernetesClusterBasicWithoutReader context m, HasNixContext context
  )
  -- | Options
  => KataContainersOptions
  -> SpecFree (ContextWithKataContainers context) m ()
  -> SpecFree context m ()
introduceKataContainers :: forall context (m :: * -> *).
(Typeable context, KubernetesClusterBasicWithoutReader context m,
 HasNixContext context) =>
KataContainersOptions
-> SpecFree (ContextWithKataContainers context) m ()
-> SpecFree context m ()
introduceKataContainers KataContainersOptions
options = forall (a :: Symbol) context (m :: * -> *).
(HasBaseContext context, HasNixContext context, MonadUnliftIO m,
 KnownSymbol a) =>
Text
-> SpecFree
     (LabelValue (AppendSymbol "file-" a) (EnvironmentFile a)
      :> context)
     m
     ()
-> SpecFree context m ()
introduceBinaryViaNixPackage @"kubectl" Text
"kubectl" (Free
   (SpecCommand
      (LabelValue "file-kubectl" (EnvironmentFile "kubectl") :> context)
      m)
   ()
 -> Free (SpecCommand context m) ())
-> (SpecFree (ContextWithKataContainers context) m ()
    -> Free
         (SpecCommand
            (LabelValue "file-kubectl" (EnvironmentFile "kubectl") :> context)
            m)
         ())
-> SpecFree (ContextWithKataContainers context) m ()
-> Free (SpecCommand context m) ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String
-> Label "kataContainers" KataContainersContext
-> ((HasCallStack =>
     KataContainersContext
     -> ExampleT
          (LabelValue "file-kubectl" (EnvironmentFile "kubectl") :> context)
          m
          [Result])
    -> ExampleT
         (LabelValue "file-kubectl" (EnvironmentFile "kubectl") :> context)
         m
         ())
-> SpecFree (ContextWithKataContainers context) m ()
-> Free
     (SpecCommand
        (LabelValue "file-kubectl" (EnvironmentFile "kubectl") :> context)
        m)
     ()
forall (l :: Symbol) intro context (m :: * -> *).
HasCallStack =>
String
-> Label l intro
-> ((HasCallStack => intro -> ExampleT context m [Result])
    -> ExampleT context m ())
-> SpecFree (LabelValue l intro :> context) m ()
-> SpecFree context m ()
introduceWith String
"introduce KataContainers" Label "kataContainers" KataContainersContext
kataContainers (ExampleT
  (LabelValue "file-kubectl" (EnvironmentFile "kubectl") :> context)
  m
  [Result]
-> ExampleT
     (LabelValue "file-kubectl" (EnvironmentFile "kubectl") :> context)
     m
     ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ExampleT
   (LabelValue "file-kubectl" (EnvironmentFile "kubectl") :> context)
   m
   [Result]
 -> ExampleT
      (LabelValue "file-kubectl" (EnvironmentFile "kubectl") :> context)
      m
      ())
-> ((KataContainersContext
     -> ExampleT
          (LabelValue "file-kubectl" (EnvironmentFile "kubectl") :> context)
          m
          [Result])
    -> ExampleT
         (LabelValue "file-kubectl" (EnvironmentFile "kubectl") :> context)
         m
         [Result])
-> (KataContainersContext
    -> ExampleT
         (LabelValue "file-kubectl" (EnvironmentFile "kubectl") :> context)
         m
         [Result])
-> ExampleT
     (LabelValue "file-kubectl" (EnvironmentFile "kubectl") :> context)
     m
     ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KataContainersOptions
-> (KataContainersContext
    -> ExampleT
         (LabelValue "file-kubectl" (EnvironmentFile "kubectl") :> context)
         m
         [Result])
-> ExampleT
     (LabelValue "file-kubectl" (EnvironmentFile "kubectl") :> context)
     m
     [Result]
forall context (m :: * -> *) a.
(HasCallStack, Typeable context, MonadFail m,
 KubectlBasic context m) =>
KataContainersOptions -> (KataContainersContext -> m a) -> m a
withKataContainers KataContainersOptions
options)

-- | Bracket-style version of 'introduceKataContainers'.
withKataContainers :: forall context m a. (
  HasCallStack, Typeable context, MonadFail m, KubectlBasic context m
  )
  -- | Options
  => KataContainersOptions
  -> (KataContainersContext -> m a)
  -> m a
withKataContainers :: forall context (m :: * -> *) a.
(HasCallStack, Typeable context, MonadFail m,
 KubectlBasic context m) =>
KataContainersOptions -> (KataContainersContext -> m a) -> m a
withKataContainers KataContainersOptions
options KataContainersContext -> m a
action = do
  kcc <- 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
  kubectlBinary <- askFile @"kubectl"
  withKataContainers' kcc kubectlBinary options action

-- | Same as 'withKataContainers', but allows you to pass in the 'KubernetesClusterContext' and @kubectl@ binary path.
withKataContainers' :: forall context m a. (
  HasCallStack, Typeable context, MonadFail m, KubernetesBasic context m
  )
  => KubernetesClusterContext
  -- | Path to @kubectl@ binary
  -> FilePath
  -> KataContainersOptions
  -> (KataContainersContext -> m a)
  -> m a
withKataContainers' :: forall context (m :: * -> *) a.
(HasCallStack, Typeable context, MonadFail m,
 KubernetesBasic context m) =>
KubernetesClusterContext
-> String
-> KataContainersOptions
-> (KataContainersContext -> m a)
-> m a
withKataContainers' kcc :: KubernetesClusterContext
kcc@(KubernetesClusterContext {Int
String
(Manager, KubernetesClientConfig)
Text
KubernetesClusterType
kubernetesClusterName :: Text
kubernetesClusterKubeConfigPath :: String
kubernetesClusterNumNodes :: Int
kubernetesClusterClientConfig :: (Manager, KubernetesClientConfig)
kubernetesClusterType :: KubernetesClusterType
kubernetesClusterType :: KubernetesClusterContext -> KubernetesClusterType
kubernetesClusterClientConfig :: KubernetesClusterContext -> (Manager, KubernetesClientConfig)
kubernetesClusterNumNodes :: KubernetesClusterContext -> Int
kubernetesClusterKubeConfigPath :: KubernetesClusterContext -> String
kubernetesClusterName :: KubernetesClusterContext -> Text
..}) String
kubectlBinary options :: KataContainersOptions
options@(KataContainersOptions {Bool
Maybe Text
SourceCheckout
kataContainersSourceCheckout :: KataContainersOptions -> SourceCheckout
kataContainersKataDeployImage :: KataContainersOptions -> Maybe Text
kataContainersPreloadImages :: KataContainersOptions -> Bool
kataContainersLabelNode :: KataContainersOptions -> Bool
kataContainersSourceCheckout :: SourceCheckout
kataContainersKataDeployImage :: Maybe Text
kataContainersPreloadImages :: Bool
kataContainersLabelNode :: Bool
..}) KataContainersContext -> m a
action = do
  -- Preflight checks
  case KubernetesClusterType
kubernetesClusterType of
    KubernetesClusterKind {} -> String -> m ()
forall (m :: * -> *) a. (HasCallStack, MonadIO m) => String -> m a
expectationFailure [i|Can't install Kata Containers on Kind at present.|]
    KubernetesClusterMinikube {String
[Text]
Text
kubernetesClusterTypeMinikubeBinary :: String
kubernetesClusterTypeMinikubeProfileName :: Text
kubernetesClusterTypeMinikubeFlags :: [Text]
kubernetesClusterTypeMinikubeFlags :: KubernetesClusterType -> [Text]
kubernetesClusterTypeMinikubeProfileName :: KubernetesClusterType -> Text
kubernetesClusterTypeMinikubeBinary :: KubernetesClusterType -> String
..} -> do
      output <- CreateProcess -> String -> m String
forall (m :: * -> *).
(HasCallStack, MonadUnliftIO m, MonadLogger m) =>
CreateProcess -> String -> m String
readCreateProcessWithLogging (String -> [String] -> CreateProcess
proc String
kubernetesClusterTypeMinikubeBinary [
                                                 String
"--profile", Text -> String
forall a. ToString a => a -> String
toString Text
kubernetesClusterTypeMinikubeProfileName
                                                 , String
"ssh", [i|egrep -c 'vmx|svm' /proc/cpuinfo|]
                                                 ]) String
""
      case readMay output of
        Just (Int
0 :: Int) -> String -> m ()
forall (m :: * -> *) a. (HasCallStack, MonadIO m) => String -> m a
expectationFailure [i|Preflight check: didn't find "vmx" or "svm" in /proc/cpuinfo. Please make sure virtualization support is enabled.|]
        Just Int
_ -> () -> m ()
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        Maybe Int
Nothing -> String -> m ()
forall (m :: * -> *) a. (HasCallStack, MonadIO m) => String -> m a
expectationFailure [i|Preflight check: couldn't parse output of minikube ssh "egrep -c 'vmx|svm' /proc/cpuinfo"|]

  -- Get Kata source dir
  kataRoot <- case SourceCheckout
kataContainersSourceCheckout of
    SourceCheckoutFilePath String
x -> String -> m String
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure String
x
    SourceCheckoutNixDerivation Text
d -> Label "nixContext" NixContext -> m (Maybe NixContext)
forall context (m :: * -> *) (l :: Symbol) a.
(MonadReader context m, KnownSymbol l, Typeable context,
 Typeable a) =>
Label l a -> m (Maybe a)
getContextMaybe Label "nixContext" NixContext
nixContext m (Maybe NixContext) -> (Maybe NixContext -> m String) -> m String
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
      Maybe NixContext
Nothing -> String -> m String
forall (m :: * -> *) a. (HasCallStack, MonadIO m) => String -> m a
expectationFailure [i|Wanted to build Kata Containers source checkout via derivation, but no Nix context was provided.|]
      Just NixContext
nc -> NixContext -> Text -> m String
forall context (m :: * -> *).
(HasBaseContextMonad context m, MonadUnliftIO m, MonadLogger m) =>
NixContext -> Text -> m String
buildNixCallPackageDerivation' NixContext
nc Text
d

  info [i|kataRoot: #{kataRoot}|]

  env <- getKubectlEnvironment kcc

  -- Now follow the instructions from
  -- https://github.com/kata-containers/kata-containers/blob/main/docs/install/minikube-installation-guide.md#installing-kata-containers

  -- Read the RBAC and DaemonSet configs
  rbacContents <- liftIO $ T.readFile $ kataRoot </> "tools/packaging/kata-deploy/kata-rbac/base/kata-rbac.yaml"
  deploymentContents' <- liftIO $ T.readFile $ kataRoot </> "tools/packaging/kata-deploy/kata-deploy/base/kata-deploy.yaml"
  let deploymentContents = case Maybe Text
kataContainersKataDeployImage of
        Maybe Text
Nothing -> Text
deploymentContents'
        Just Text
deployImage -> Text
deploymentContents'
                          Text -> (Text -> Text) -> Text
forall a b. a -> (a -> b) -> b
& Text -> Text -> Text
setDaemonSetImage Text
deployImage

  -- Preload any images
  when kataContainersPreloadImages $ do
    let images = Text -> [Text]
findAllImages (Text
rbacContents Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n---\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
deploymentContents)

    forM_ images $ \Text
image -> do
      Text -> m ()
forall (m :: * -> *). (HasCallStack, MonadLogger m) => Text -> m ()
info [i|Preloading image: #{image}|]
      KubernetesClusterContext -> ImageLoadSpec -> m ()
forall (m :: * -> *) context.
(HasCallStack, MonadFail m, KubernetesBasic context m) =>
KubernetesClusterContext -> ImageLoadSpec -> m ()
loadImageIfNecessary' KubernetesClusterContext
kcc (Text -> ImagePullPolicy -> ImageLoadSpec
ImageLoadSpecDocker Text
image ImagePullPolicy
IfNotPresent)

  -- Install kata-deploy
  debug [i|Applying kata-rbac.yaml|]
  createProcessWithLoggingAndStdin ((proc kubectlBinary ["apply", "-f", "-"]) { env = Just env }) (toString rbacContents)
    >>= waitForProcess >>= (`shouldBe` ExitSuccess)
  debug [i|Applying kata-deploy.yaml|]
  createProcessWithLoggingAndStdin ((proc kubectlBinary ["apply", "-f", "-"]) { env = Just env }) (toString deploymentContents)
    >>= waitForProcess >>= (`shouldBe` ExitSuccess)

  debug [i|Waiting for kata-deploy pod to exist|]
  podName <- waitUntil 600 $ do
    pods <- (T.words . toText) <$> readCreateProcessWithLogging ((
      (proc kubectlBinary ["-n", "kube-system"
                          , "get", "pods", "-o=name"]) { env = Just env }
      ) { env = Just env }) ""

    case headMay [t | t <- pods, "pod/kata-deploy" `T.isPrefixOf` t] of
      Just Text
x -> Text -> m Text
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Text
x
      Maybe Text
Nothing -> String -> m Text
forall (m :: * -> *) a. (HasCallStack, MonadIO m) => String -> m a
expectationFailure [i|Couldn't find kata-deploy pod in: #{pods}|]

  info [i|Got podName: #{podName}|]

  -- Wait until the kata-deploy pod starts sleeping
  waitUntil 600 $ do
    (exitCode, sout, serr) <- readCreateProcessWithExitCode (
      (proc kubectlBinary ["-n", "kube-system"
                          , "exec", toString podName
                          , "--"
                          , "ps", "-ef"
                          ])
      { env = Just env }
      ) ""
    case exitCode of
      ExitCode
ExitSuccess -> () -> m ()
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      ExitFailure Int
n -> String -> m ()
forall (m :: * -> *) a. (HasCallStack, MonadIO m) => String -> m a
expectationFailure [i|Command failed with code #{n}. Stderr: #{serr}|]

    toText sout `textShouldContain` "sleep infinity"

  -- Now install the runtime classes
  debug [i|Applying kata-runtimeClasses.yaml|]
  runtimeClassesContents <- liftIO $ T.readFile $ kataRoot </> "tools/packaging/kata-deploy/runtimeclasses/kata-runtimeClasses.yaml"
  createProcessWithLoggingAndStdin ((proc kubectlBinary ["apply", "-f", "-"]) { env = Just env }) (toString runtimeClassesContents)
    >>= waitForProcess >>= (`shouldBe` ExitSuccess)

  -- Finally, label the node(s)
  debug [i|Labeling nodes with katacontainers.io/kata-runtime=true|]
  when kataContainersLabelNode $ do
    createProcessWithLoggingAndStdin ((proc kubectlBinary ["label", "nodes", "--all", "--overwrite", "katacontainers.io/kata-runtime=true"]) { env = Just env }) (toString deploymentContents)
      >>= waitForProcess >>= (`shouldBe` ExitSuccess)

  action $ KataContainersContext options

kataContainersDeployImage :: Text
kataContainersDeployImage :: Text
kataContainersDeployImage = Text
"quay.io/kata-containers/kata-deploy:3.19.1"

-- | Checkout of the @kata-containers@ repo. Currently at release 3.19.1.
kataContainersDerivation :: Text
kataContainersDerivation :: Text
kataContainersDerivation = [__i|{fetchFromGitHub}:

                                fetchFromGitHub {
                                  owner = "kata-containers";
                                  repo = "kata-containers";
                                  rev = "acae4480ac84701d7354e679714cc9d084b37f44";
                                  sha256 = "sha256-h9Jsto2l1NhQEwIQoecT/D+yt/QbGoqqH/l6NNzJOwk=";
                                }
                               |]

setDaemonSetImage :: Text -> Text -> Text
setDaemonSetImage :: Text -> Text -> Text
setDaemonSetImage Text
image = [Text] -> Text
forall a. Monoid a => [a] -> a
mconcat ([Text] -> Text) -> (Text -> [Text]) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Text) -> [Text] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> Text
setDaemonSetImage' ([Text] -> [Text]) -> (Text -> [Text]) -> Text -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HasCallStack => Text -> Text -> [Text]
Text -> Text -> [Text]
T.splitOn Text
"---\n"
  where
    setDaemonSetImage' :: Text -> Text
    setDaemonSetImage' :: Text -> Text
setDaemonSetImage' (Text -> Either ParseException V1DaemonSet
forall a. FromJSON a => Text -> Either ParseException a
decode -> Right x :: V1DaemonSet
x@(V1DaemonSet {v1DaemonSetKind :: V1DaemonSet -> Maybe Text
v1DaemonSetKind=(Just Text
"DaemonSet")})) = V1DaemonSet
x
      V1DaemonSet -> (V1DaemonSet -> V1DaemonSet) -> V1DaemonSet
forall a b. a -> (a -> b) -> b
& ASetter V1DaemonSet V1DaemonSet (Maybe Text) (Maybe Text)
-> Maybe Text -> V1DaemonSet -> V1DaemonSet
forall s t a b. ASetter s t a b -> b -> s -> t
set ((Maybe V1DaemonSetSpec -> Identity (Maybe V1DaemonSetSpec))
-> V1DaemonSet -> Identity V1DaemonSet
Lens_' V1DaemonSet (Maybe V1DaemonSetSpec)
v1DaemonSetSpecL ((Maybe V1DaemonSetSpec -> Identity (Maybe V1DaemonSetSpec))
 -> V1DaemonSet -> Identity V1DaemonSet)
-> ((Maybe Text -> Identity (Maybe Text))
    -> Maybe V1DaemonSetSpec -> Identity (Maybe V1DaemonSetSpec))
-> ASetter V1DaemonSet V1DaemonSet (Maybe Text) (Maybe Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (V1DaemonSetSpec -> Identity V1DaemonSetSpec)
-> Maybe V1DaemonSetSpec -> Identity (Maybe V1DaemonSetSpec)
forall a b (p :: * -> * -> *) (f :: * -> *).
(Choice p, Applicative f) =>
p a (f b) -> p (Maybe a) (f (Maybe b))
_Just ((V1DaemonSetSpec -> Identity V1DaemonSetSpec)
 -> Maybe V1DaemonSetSpec -> Identity (Maybe V1DaemonSetSpec))
-> ((Maybe Text -> Identity (Maybe Text))
    -> V1DaemonSetSpec -> Identity V1DaemonSetSpec)
-> (Maybe Text -> Identity (Maybe Text))
-> Maybe V1DaemonSetSpec
-> Identity (Maybe V1DaemonSetSpec)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (V1PodTemplateSpec -> Identity V1PodTemplateSpec)
-> V1DaemonSetSpec -> Identity V1DaemonSetSpec
Lens_' V1DaemonSetSpec V1PodTemplateSpec
v1DaemonSetSpecTemplateL ((V1PodTemplateSpec -> Identity V1PodTemplateSpec)
 -> V1DaemonSetSpec -> Identity V1DaemonSetSpec)
-> ((Maybe Text -> Identity (Maybe Text))
    -> V1PodTemplateSpec -> Identity V1PodTemplateSpec)
-> (Maybe Text -> Identity (Maybe Text))
-> V1DaemonSetSpec
-> Identity V1DaemonSetSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe V1PodSpec -> Identity (Maybe V1PodSpec))
-> V1PodTemplateSpec -> Identity V1PodTemplateSpec
Lens_' V1PodTemplateSpec (Maybe V1PodSpec)
v1PodTemplateSpecSpecL ((Maybe V1PodSpec -> Identity (Maybe V1PodSpec))
 -> V1PodTemplateSpec -> Identity V1PodTemplateSpec)
-> ((Maybe Text -> Identity (Maybe Text))
    -> Maybe V1PodSpec -> Identity (Maybe V1PodSpec))
-> (Maybe Text -> Identity (Maybe Text))
-> V1PodTemplateSpec
-> Identity V1PodTemplateSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (V1PodSpec -> Identity V1PodSpec)
-> Maybe V1PodSpec -> Identity (Maybe V1PodSpec)
forall a b (p :: * -> * -> *) (f :: * -> *).
(Choice p, Applicative f) =>
p a (f b) -> p (Maybe a) (f (Maybe b))
_Just ((V1PodSpec -> Identity V1PodSpec)
 -> Maybe V1PodSpec -> Identity (Maybe V1PodSpec))
-> ((Maybe Text -> Identity (Maybe Text))
    -> V1PodSpec -> Identity V1PodSpec)
-> (Maybe Text -> Identity (Maybe Text))
-> Maybe V1PodSpec
-> Identity (Maybe V1PodSpec)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([V1Container] -> Identity [V1Container])
-> V1PodSpec -> Identity V1PodSpec
Lens_' V1PodSpec [V1Container]
v1PodSpecContainersL (([V1Container] -> Identity [V1Container])
 -> V1PodSpec -> Identity V1PodSpec)
-> ((Maybe Text -> Identity (Maybe Text))
    -> [V1Container] -> Identity [V1Container])
-> (Maybe Text -> Identity (Maybe Text))
-> V1PodSpec
-> Identity V1PodSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Index [V1Container]
-> Traversal' [V1Container] (IxValue [V1Container])
forall m. Ixed m => Index m -> Traversal' m (IxValue m)
ix Int
Index [V1Container]
0 ((V1Container -> Identity V1Container)
 -> [V1Container] -> Identity [V1Container])
-> ((Maybe Text -> Identity (Maybe Text))
    -> V1Container -> Identity V1Container)
-> (Maybe Text -> Identity (Maybe Text))
-> [V1Container]
-> Identity [V1Container]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe Text -> Identity (Maybe Text))
-> V1Container -> Identity V1Container
Lens_' V1Container (Maybe Text)
v1ContainerImageL) (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
image)
      V1DaemonSet -> (V1DaemonSet -> V1DaemonSet) -> V1DaemonSet
forall a b. a -> (a -> b) -> b
& ASetter V1DaemonSet V1DaemonSet (Maybe Text) (Maybe Text)
-> Maybe Text -> V1DaemonSet -> V1DaemonSet
forall s t a b. ASetter s t a b -> b -> s -> t
set ((Maybe V1DaemonSetSpec -> Identity (Maybe V1DaemonSetSpec))
-> V1DaemonSet -> Identity V1DaemonSet
Lens_' V1DaemonSet (Maybe V1DaemonSetSpec)
v1DaemonSetSpecL ((Maybe V1DaemonSetSpec -> Identity (Maybe V1DaemonSetSpec))
 -> V1DaemonSet -> Identity V1DaemonSet)
-> ((Maybe Text -> Identity (Maybe Text))
    -> Maybe V1DaemonSetSpec -> Identity (Maybe V1DaemonSetSpec))
-> ASetter V1DaemonSet V1DaemonSet (Maybe Text) (Maybe Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (V1DaemonSetSpec -> Identity V1DaemonSetSpec)
-> Maybe V1DaemonSetSpec -> Identity (Maybe V1DaemonSetSpec)
forall a b (p :: * -> * -> *) (f :: * -> *).
(Choice p, Applicative f) =>
p a (f b) -> p (Maybe a) (f (Maybe b))
_Just ((V1DaemonSetSpec -> Identity V1DaemonSetSpec)
 -> Maybe V1DaemonSetSpec -> Identity (Maybe V1DaemonSetSpec))
-> ((Maybe Text -> Identity (Maybe Text))
    -> V1DaemonSetSpec -> Identity V1DaemonSetSpec)
-> (Maybe Text -> Identity (Maybe Text))
-> Maybe V1DaemonSetSpec
-> Identity (Maybe V1DaemonSetSpec)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (V1PodTemplateSpec -> Identity V1PodTemplateSpec)
-> V1DaemonSetSpec -> Identity V1DaemonSetSpec
Lens_' V1DaemonSetSpec V1PodTemplateSpec
v1DaemonSetSpecTemplateL ((V1PodTemplateSpec -> Identity V1PodTemplateSpec)
 -> V1DaemonSetSpec -> Identity V1DaemonSetSpec)
-> ((Maybe Text -> Identity (Maybe Text))
    -> V1PodTemplateSpec -> Identity V1PodTemplateSpec)
-> (Maybe Text -> Identity (Maybe Text))
-> V1DaemonSetSpec
-> Identity V1DaemonSetSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe V1PodSpec -> Identity (Maybe V1PodSpec))
-> V1PodTemplateSpec -> Identity V1PodTemplateSpec
Lens_' V1PodTemplateSpec (Maybe V1PodSpec)
v1PodTemplateSpecSpecL ((Maybe V1PodSpec -> Identity (Maybe V1PodSpec))
 -> V1PodTemplateSpec -> Identity V1PodTemplateSpec)
-> ((Maybe Text -> Identity (Maybe Text))
    -> Maybe V1PodSpec -> Identity (Maybe V1PodSpec))
-> (Maybe Text -> Identity (Maybe Text))
-> V1PodTemplateSpec
-> Identity V1PodTemplateSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (V1PodSpec -> Identity V1PodSpec)
-> Maybe V1PodSpec -> Identity (Maybe V1PodSpec)
forall a b (p :: * -> * -> *) (f :: * -> *).
(Choice p, Applicative f) =>
p a (f b) -> p (Maybe a) (f (Maybe b))
_Just ((V1PodSpec -> Identity V1PodSpec)
 -> Maybe V1PodSpec -> Identity (Maybe V1PodSpec))
-> ((Maybe Text -> Identity (Maybe Text))
    -> V1PodSpec -> Identity V1PodSpec)
-> (Maybe Text -> Identity (Maybe Text))
-> Maybe V1PodSpec
-> Identity (Maybe V1PodSpec)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([V1Container] -> Identity [V1Container])
-> V1PodSpec -> Identity V1PodSpec
Lens_' V1PodSpec [V1Container]
v1PodSpecContainersL (([V1Container] -> Identity [V1Container])
 -> V1PodSpec -> Identity V1PodSpec)
-> ((Maybe Text -> Identity (Maybe Text))
    -> [V1Container] -> Identity [V1Container])
-> (Maybe Text -> Identity (Maybe Text))
-> V1PodSpec
-> Identity V1PodSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Index [V1Container]
-> Traversal' [V1Container] (IxValue [V1Container])
forall m. Ixed m => Index m -> Traversal' m (IxValue m)
ix Int
Index [V1Container]
0 ((V1Container -> Identity V1Container)
 -> [V1Container] -> Identity [V1Container])
-> ((Maybe Text -> Identity (Maybe Text))
    -> V1Container -> Identity V1Container)
-> (Maybe Text -> Identity (Maybe Text))
-> [V1Container]
-> Identity [V1Container]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe Text -> Identity (Maybe Text))
-> V1Container -> Identity V1Container
Lens_' V1Container (Maybe Text)
v1ContainerImagePullPolicyL) (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"IfNotPresent")
      V1DaemonSet -> (V1DaemonSet -> ByteString) -> ByteString
forall a b. a -> (a -> b) -> b
& V1DaemonSet -> ByteString
forall a. ToJSON a => a -> ByteString
Yaml.encode
      ByteString -> (ByteString -> Text) -> Text
forall a b. a -> (a -> b) -> b
& ByteString -> Text
forall a b. ConvertUtf8 a b => b -> a
decodeUtf8
    setDaemonSetImage' Text
t = Text
t

decode :: FromJSON a => Text -> Either Yaml.ParseException a
decode :: forall a. FromJSON a => Text -> Either ParseException a
decode = ByteString -> Either ParseException a
forall a. FromJSON a => ByteString -> Either ParseException a
Yaml.decodeEither' (ByteString -> Either ParseException a)
-> (Text -> ByteString) -> Text -> Either ParseException a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
forall a b. ConvertUtf8 a b => a -> b
encodeUtf8