git-annex/Assistant/WebApp/Configurators/AWS.hs

242 lines
7.7 KiB
Haskell
Raw Normal View History

2012-11-24 20:30:15 +00:00
{- git-annex assistant webapp configurators for Amazon AWS services
-
- Copyright 2012 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU AGPL version 3 or higher.
-}
{-# LANGUAGE CPP, FlexibleContexts, TypeFamilies, QuasiQuotes, MultiParamTypeClasses, TemplateHaskell, OverloadedStrings, RankNTypes #-}
2012-11-24 20:30:15 +00:00
module Assistant.WebApp.Configurators.AWS where
2012-11-25 04:26:46 +00:00
import Assistant.WebApp.Common
2012-11-24 20:30:15 +00:00
import Assistant.MakeRemote
import Assistant.Sync
#ifdef WITH_S3
import qualified Remote.S3 as S3
#endif
import qualified Remote.Glacier as Glacier
import qualified Remote.Helper.AWS as AWS
import Logs.Remote
import qualified Remote
import qualified Types.Remote as Remote
2012-11-24 20:30:15 +00:00
import Types.Remote (RemoteConfig)
import Types.StandardGroups
import Logs.PreferredContent
import Creds
2012-11-24 20:30:15 +00:00
import qualified Data.Text as T
import qualified Data.Map as M
import Data.Char
2012-11-24 20:30:15 +00:00
awsConfigurator :: Widget -> Handler RepHtml
awsConfigurator = page "Add an Amazon repository" (Just Configuration)
2012-11-24 20:30:15 +00:00
glacierConfigurator :: Widget -> Handler RepHtml
glacierConfigurator a = do
ifM (liftIO $ inPath "glacier")
( awsConfigurator a
, awsConfigurator needglaciercli
)
where
needglaciercli = $(widgetFile "configurators/needglaciercli")
data StorageClass = StandardRedundancy | ReducedRedundancy
deriving (Eq, Enum, Bounded)
instance Show StorageClass where
show StandardRedundancy = "STANDARD"
show ReducedRedundancy = "REDUCED_REDUNDANCY"
data AWSInput = AWSInput
{ accessKeyID :: Text
, secretAccessKey :: Text
, datacenter :: Text
-- Only used for S3, not Glacier.
, storageClass :: StorageClass
, repoName :: Text
, enableEncryption :: EnableEncryption
2012-11-24 20:30:15 +00:00
}
data AWSCreds = AWSCreds Text Text
extractCreds :: AWSInput -> AWSCreds
extractCreds i = AWSCreds (accessKeyID i) (secretAccessKey i)
2013-06-02 19:57:22 +00:00
s3InputAForm :: Maybe CredPair -> AForm Handler AWSInput
s3InputAForm defcreds = AWSInput
<$> accessKeyIDFieldWithHelp (T.pack . fst <$> defcreds)
<*> secretAccessKeyField (T.pack . snd <$> defcreds)
<*> datacenterField AWS.S3
2012-11-24 20:30:15 +00:00
<*> areq (selectFieldList storageclasses) "Storage class" (Just StandardRedundancy)
<*> areq textField "Repository name" (Just "S3")
<*> enableEncryptionField
2012-11-24 20:30:15 +00:00
where
storageclasses :: [(Text, StorageClass)]
storageclasses =
[ ("Standard redundancy", StandardRedundancy)
, ("Reduced redundancy (costs less)", ReducedRedundancy)
]
2013-06-02 19:57:22 +00:00
glacierInputAForm :: Maybe CredPair -> AForm Handler AWSInput
glacierInputAForm defcreds = AWSInput
<$> accessKeyIDFieldWithHelp (T.pack . fst <$> defcreds)
<*> secretAccessKeyField (T.pack . snd <$> defcreds)
<*> datacenterField AWS.Glacier
2012-11-24 20:30:15 +00:00
<*> pure StandardRedundancy
<*> areq textField "Repository name" (Just "glacier")
<*> enableEncryptionField
2012-11-24 20:30:15 +00:00
2013-06-02 19:57:22 +00:00
awsCredsAForm :: Maybe CredPair -> AForm Handler AWSCreds
awsCredsAForm defcreds = AWSCreds
<$> accessKeyIDFieldWithHelp (T.pack . fst <$> defcreds)
<*> secretAccessKeyField (T.pack . snd <$> defcreds)
2013-06-02 19:57:22 +00:00
accessKeyIDField :: Widget -> Maybe Text -> AForm Handler Text
accessKeyIDField help def = areq (textField `withNote` help) "Access Key ID" def
2013-06-02 19:57:22 +00:00
accessKeyIDFieldWithHelp :: Maybe Text -> AForm Handler Text
accessKeyIDFieldWithHelp def = accessKeyIDField help def
where
help = [whamlet|
<a href="https://portal.aws.amazon.com/gp/aws/securityCredentials#id_block">
Get Amazon access keys
|]
2013-06-02 19:57:22 +00:00
secretAccessKeyField :: Maybe Text -> AForm Handler Text
secretAccessKeyField def = areq passwordField "Secret Access Key" def
2013-06-02 19:57:22 +00:00
datacenterField :: AWS.Service -> AForm Handler Text
datacenterField service = areq (selectFieldList list) "Datacenter" defregion
where
list = M.toList $ AWS.regionMap service
defregion = Just $ AWS.defaultRegion service
2012-11-24 20:30:15 +00:00
getAddS3R :: Handler RepHtml
2013-03-16 22:48:23 +00:00
getAddS3R = postAddS3R
postAddS3R :: Handler RepHtml
2012-11-24 20:30:15 +00:00
#ifdef WITH_S3
2013-03-16 22:48:23 +00:00
postAddS3R = awsConfigurator $ do
defcreds <- liftAnnex previouslyUsedAWSCreds
2013-06-02 19:57:22 +00:00
((result, form), enctype) <- handlerToWidget $
runFormPost $ renderBootstrap $ s3InputAForm defcreds
2012-11-24 20:30:15 +00:00
case result of
2013-06-02 19:57:22 +00:00
FormSuccess input -> handlerToWidget $ do
2012-11-24 20:30:15 +00:00
let name = T.unpack $ repoName input
makeAWSRemote S3.remote (extractCreds input) name setgroup $ M.fromList
[ configureEncryption $ enableEncryption input
2012-11-24 20:30:15 +00:00
, ("type", "S3")
, ("datacenter", T.unpack $ datacenter input)
, ("storageclass", show $ storageClass input)
]
2012-11-25 04:38:11 +00:00
_ -> $(widgetFile "configurators/adds3")
2012-11-24 20:30:15 +00:00
where
setgroup r = liftAnnex $
2012-11-24 20:30:15 +00:00
setStandardGroup (Remote.uuid r) TransferGroup
#else
2013-03-16 22:48:23 +00:00
postAddS3R = error "S3 not supported by this build"
2012-11-24 20:30:15 +00:00
#endif
getAddGlacierR :: Handler RepHtml
2013-03-16 22:48:23 +00:00
getAddGlacierR = postAddGlacierR
postAddGlacierR :: Handler RepHtml
#ifdef WITH_S3
2013-03-16 22:48:23 +00:00
postAddGlacierR = glacierConfigurator $ do
defcreds <- liftAnnex previouslyUsedAWSCreds
2013-06-02 19:57:22 +00:00
((result, form), enctype) <- handlerToWidget $
runFormPost $ renderBootstrap $ glacierInputAForm defcreds
2012-11-24 20:30:15 +00:00
case result of
2013-06-02 19:57:22 +00:00
FormSuccess input -> handlerToWidget $ do
2012-11-24 20:30:15 +00:00
let name = T.unpack $ repoName input
makeAWSRemote Glacier.remote (extractCreds input) name setgroup $ M.fromList
[ configureEncryption $ enableEncryption input
2012-11-24 20:30:15 +00:00
, ("type", "glacier")
, ("datacenter", T.unpack $ datacenter input)
]
2012-11-25 04:38:11 +00:00
_ -> $(widgetFile "configurators/addglacier")
2012-11-24 20:30:15 +00:00
where
setgroup r = liftAnnex $
2012-11-24 20:30:15 +00:00
setStandardGroup (Remote.uuid r) SmallArchiveGroup
#else
postAddGlacierR = error "S3 not supported by this build"
#endif
2012-11-24 20:30:15 +00:00
getEnableS3R :: UUID -> Handler RepHtml
2013-04-26 20:07:55 +00:00
#ifdef WITH_S3
2013-04-25 17:14:49 +00:00
getEnableS3R uuid = do
m <- liftAnnex readRemoteLog
if isIARemoteConfig $ fromJust $ M.lookup uuid m
2013-04-25 17:14:49 +00:00
then redirect $ EnableIAR uuid
else postEnableS3R uuid
2013-04-26 20:07:55 +00:00
#else
getEnableS3R = postEnableS3R
#endif
2013-03-16 22:48:23 +00:00
postEnableS3R :: UUID -> Handler RepHtml
2012-11-24 20:30:15 +00:00
#ifdef WITH_S3
2013-04-25 17:14:49 +00:00
postEnableS3R uuid = awsConfigurator $ enableAWSRemote S3.remote uuid
2012-11-24 20:30:15 +00:00
#else
2013-03-16 22:48:23 +00:00
postEnableS3R _ = error "S3 not supported by this build"
2012-11-24 20:30:15 +00:00
#endif
getEnableGlacierR :: UUID -> Handler RepHtml
2013-03-16 22:48:23 +00:00
getEnableGlacierR = postEnableGlacierR
postEnableGlacierR :: UUID -> Handler RepHtml
postEnableGlacierR = glacierConfigurator . enableAWSRemote Glacier.remote
2012-11-24 20:30:15 +00:00
enableAWSRemote :: RemoteType -> UUID -> Widget
#ifdef WITH_S3
2012-11-24 20:30:15 +00:00
enableAWSRemote remotetype uuid = do
defcreds <- liftAnnex previouslyUsedAWSCreds
2013-06-02 19:57:22 +00:00
((result, form), enctype) <- handlerToWidget $
runFormPost $ renderBootstrap $ awsCredsAForm defcreds
2012-11-24 20:30:15 +00:00
case result of
2013-06-02 19:57:22 +00:00
FormSuccess creds -> handlerToWidget $ do
m <- liftAnnex readRemoteLog
2012-11-24 20:30:15 +00:00
let name = fromJust $ M.lookup "name" $
fromJust $ M.lookup uuid m
makeAWSRemote remotetype creds name (const noop) M.empty
_ -> do
description <- liftAnnex $
T.pack <$> Remote.prettyUUID uuid
2012-11-24 20:30:15 +00:00
$(widgetFile "configurators/enableaws")
#else
enableAWSRemote _ _ = error "S3 not supported by this build"
#endif
2012-11-24 20:30:15 +00:00
makeAWSRemote :: RemoteType -> AWSCreds -> String -> (Remote -> Handler ()) -> RemoteConfig -> Handler ()
makeAWSRemote remotetype (AWSCreds ak sk) name setup config = do
remotename <- liftAnnex $ fromRepo $ uniqueRemoteName name 0
2012-11-24 20:30:15 +00:00
liftIO $ AWS.setCredsEnv (T.unpack ak, T.unpack sk)
r <- liftAnnex $ addRemote $ do
makeSpecialRemote hostname remotetype config
2012-11-24 20:30:15 +00:00
return remotename
setup r
liftAssistant $ syncRemote r
2012-11-24 20:30:15 +00:00
redirect $ EditNewCloudRepositoryR $ Remote.uuid r
where
{- AWS services use the remote name as the basis for a host
- name, so filter it to contain valid characters. -}
hostname = case filter isAlphaNum name of
[] -> "aws"
n -> n
getRepoInfo :: RemoteConfig -> Widget
getRepoInfo c = [whamlet|S3 remote using bucket: #{bucket}|]
where
bucket = fromMaybe "" $ M.lookup "bucket" c
#ifdef WITH_S3
isIARemoteConfig :: RemoteConfig -> Bool
isIARemoteConfig = S3.isIAHost . fromMaybe "" . M.lookup "host"
previouslyUsedAWSCreds :: Annex (Maybe CredPair)
previouslyUsedAWSCreds = getM gettype [S3.remote, Glacier.remote]
where
gettype t = previouslyUsedCredPair AWS.creds t $
not . isIARemoteConfig . Remote.config
#endif