packages feed

keystore-0.8.2.0: examples/deploy/Deploy/Cmd.hs

{-# LANGUAGE OverloadedStrings          #-}
{-# OPTIONS_GHC -fno-warn-unused-imports#-}

module Deploy.Cmd
    ( CtxCmd(..)
    , Cmd(..)
    , parseCLI
    ) where

import           Deploy.HostSectionKey
import           Data.KeyStore
import           Data.Monoid
import           Options.Applicative
import           System.Environment


data CtxCmd =
    CtxCmd
        { cc_params :: CtxParams
        , cc_cmd    :: Cmd
        }
    deriving (Show)

data Cmd
    = C_create
    | C_rotate        (Maybe HostID)  (Maybe SectionID)  (Maybe KeyID)
    | C_rotate_smart  (Maybe HostID)  (Maybe SectionID)  (Maybe KeyID)
    | C_deploy        Bool (Maybe FilePath) HostID
    | C_client
    | C_sign
    | C_verify
    | C_list_hosts
    | C_info_key      (Maybe KeyID    )
    | C_info_section  (Maybe SectionID)
    | C_secret_script
    | C_public_script
    | C_sample_script
    | C_ks CLI
    | C_pm (PMCommand SectionID)
    deriving (Show)

parseCLI :: PMConfig SectionID -> IO CtxCmd
parseCLI pmc = getArgs >>= runParse (pi_cli $ p_cli pmc)

pi_cli :: Parser CtxCmd -> ParserInfo CtxCmd
pi_cli psr =
    h_info psr $
        fullDesc   <>
        progDesc "For carrying out deployments from the keystore."

p_cli :: PMConfig SectionID -> Parser CtxCmd
p_cli pmc = CtxCmd <$> paramsParser <*> (p_command pmc)

p_command :: PMConfig SectionID -> Parser Cmd
p_command pmc =
    subparser
     $  command "create"                    pi_create
     <> command "rotate"                   (pi_rotate_key False)
     <> command "rotate-smart"             (pi_rotate_key True )
     <> command "deploy"                    pi_deploy
     <> command "client"                    pi_client
     <> command "sign"                      pi_sign
     <> command "verify"                    pi_verify
     <> command "list-hosts"                pi_list_hosts
     <> command "info-key"                  pi_info_key
     <> command "info-section"              pi_info_section
     <> command "secret-script"             pi_secret_script
     <> command "public-script"             pi_public_script
     <> command "sample-load-script"        pi_sample_script
     <> command "ks"                        pi_ks_args
     <> command "pm"                       (pi_pm_args pmc)

pi_create :: ParserInfo Cmd
pi_create =
    h_info
        (helper <*> (pure C_create))
        (progDesc "create a new keystore")

pi_rotate_key :: Bool -> ParserInfo Cmd
pi_rotate_key sm =
    h_info
        (helper <*>
            ((if sm then C_rotate_smart else C_rotate)
                <$> optional p_host
                <*> optional p_section
                <*> optional p_key))
        (progDesc $ if sm then "rotate keys, but only if they have changed" else "rotate keys")

pi_deploy :: ParserInfo Cmd
pi_deploy =
    h_info
        (helper <*> (C_deploy <$> p_shell_flg <*> optional p_out <*> p_host_arg))
        (progDesc $ "deploy a configuration file for a host " ++
                        "(here merely generating the JSON configuration file)")

pi_client :: ParserInfo Cmd
pi_client =
    h_info
        (helper <*> (pure C_client))
        (progDesc $ "run a mock client " ++
                        "(here merely displays the session token)")


pi_sign :: ParserInfo Cmd
pi_sign =
    h_info
        (helper <*> (pure C_sign))
        (progDesc "sign the keystore")

pi_verify :: ParserInfo Cmd
pi_verify =
    h_info
        (helper <*> (pure C_verify))
        (progDesc "verify the keystore")

pi_list_hosts :: ParserInfo Cmd
pi_list_hosts =
    h_info
        (helper <*> (pure C_list_hosts))
        (progDesc "list the hosts")

pi_info_key :: ParserInfo Cmd
pi_info_key =
    h_info
        (helper <*> (C_info_key <$> optional p_key))
        (progDesc "get the gen on the keystore keys")

pi_info_section :: ParserInfo Cmd
pi_info_section =
    h_info
        (helper <*> (C_info_section <$> optional p_a_section))
        (progDesc "get the gen on the keystore sections")

pi_secret_script :: ParserInfo Cmd
pi_secret_script =
    h_info
        (helper <*> (pure C_secret_script))
        (progDesc $ "print a script to establish the all section passwords in the environment")

pi_public_script :: ParserInfo Cmd
pi_public_script =
    h_info
        (helper <*> (pure C_public_script))
        (progDesc "print a script to save the public signing key in a file")

pi_sample_script :: ParserInfo Cmd
pi_sample_script =
    h_info
        (helper <*> (pure C_sample_script))
        (progDesc "print a sample script to define keystore passwords in the environment")

pi_ks_args :: ParserInfo Cmd
pi_ks_args =
    h_info
        (helper <*> (C_ks <$> cliParser))
        (progDesc "run a ks command (see 'ks --help' for details)")

pi_pm_args :: PMConfig SectionID -> ParserInfo Cmd
pi_pm_args pmc =
    h_info
        (helper <*> (C_pm <$> pmCommandParser pmc))
        (progDesc "run a pm command (see 'pm --help' for details)")

p_shell_flg :: Parser Bool
p_shell_flg =
    switch
        (long    "shell"        <>
         help    "launch a shell with the deploy passwords setup in their environment variables")

p_host_arg :: Parser HostID
p_host_arg =
    argument (eitherReader $ maybe (Left "host not recognised") return . decode)
        $  metavar "HOST"
        <> help    "a host ID"

p_host :: Parser HostID
p_host =
    option (eitherReader $ maybe (Left "host not recognised") return . decode)
        $  long "host"
        <> metavar "HOST"
        <> help    "a host ID"

p_section :: Parser SectionID
p_section =
    option (eitherReader $ maybe (Left "section not recognised") return . decode)
        $  long "section"
        <> metavar "SECTION"
        <> help "a section ID"

p_a_section :: Parser SectionID
p_a_section =
    argument (eitherReader $ maybe (Left "section not recognised") return . decode)
        $  metavar "SECTION"
        <> help    "a section ID"

p_key :: Parser KeyID
p_key =
    option (eitherReader $ maybe (Left "key not recognised") return . decode)
        $  long     "key"
        <> metavar  "KEY"
        <> help     "a key ID"

p_out :: Parser FilePath
p_out =
    strOption
        $  long     "out"
        <> metavar  "FILE"
        <> help     "output file"

h_info :: Parser a -> InfoMod a -> ParserInfo a
h_info pr = info (helper <*> pr)