@@ -5,10 +5,10 @@
5{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7-- {-# LANGUAGE NoMonomorphismRestriction #-}
7-- {-# LANGUAGE NoMonomorphismRestriction #-}
8+{-# LANGUAGE NamedFieldPuns #-}
8{-# LANGUAGE OverloadedStrings #-}
9{-# LANGUAGE OverloadedStrings #-}
9{-# LANGUAGE RecordWildCards #-}
10{-# LANGUAGE RecordWildCards #-}
10{-# LANGUAGE UndecidableInstances #-}
11{-# LANGUAGE UndecidableInstances #-}
11−{-# LANGUAGE NamedFieldPuns #-}
13-------------------------------------------------------------------------------
13-------------------------------------------------------------------------------
@@ -69,6 +69,9 @@ module Database.Bloodhound.Types
69 , AllocationPolicy(..)
69 , AllocationPolicy(..)
70 , ReplicaBounds(..)
70 , ReplicaBounds(..)
71 , Bytes(..)
71 , Bytes(..)
72 , FSType(..)
75 , FSType(..)
73 , InitialShardCount(..)
76 , InitialShardCount(..)
74 , NodeAttrFilter(..)
77 , NodeAttrFilter(..)
@@ -235,6 +238,21 @@ module Database.Bloodhound.Types
235 , CollectionMode(..)
238 , CollectionMode(..)
236 , TermOrder(..)
239 , TermOrder(..)
237 , TermInclusion(..)
240 , TermInclusion(..)
241+ , SnapshotRepoSelection(..)
242+ , GenericSnapshotRepo(..)
244+ , SnapshotRepoConversionError(..)
245+ , SnapshotRepoType(..)
246+ , GenericSnapshotRepoSettings(..)
247+ , SnapshotRepoUpdateSettings(..)
248+ , defaultSnapshotRepoUpdateSettings
249+ , SnapshotRepoName(..)
250+ , SnapshotRepoPattern(..)
251+ , SnapshotVerification(..)
252+ , SnapshotNodeVerification(..)
255+ , FsSnapshotRepo(..)
239 , Aggregation(..)
257 , Aggregation(..)
240 , Aggregations
258 , Aggregations
@@ -275,7 +293,7 @@ module Database.Bloodhound.Types
275 , EsPassword(..)
293 , EsPassword(..)
278−import Control.Applicative
296+import Control.Applicative as A
279import Control.Monad.Catch
297import Control.Monad.Catch
280import Control.Monad.Except
298import Control.Monad.Except
281import Control.Monad.Reader
299import Control.Monad.Reader
@@ -283,7 +301,7 @@ import Control.Monad.State
283import Control.Monad.Writer
301import Control.Monad.Writer
284import Data.Aeson
302import Data.Aeson
285import Data.Aeson.Types (Pair, Parser, emptyObject,
303import Data.Aeson.Types (Pair, Parser, emptyObject,
286− parseMaybe)
304+ parseEither, parseMaybe)
287import qualified Data.ByteString.Lazy.Char8 as L
305import qualified Data.ByteString.Lazy.Char8 as L
288import Data.Char
306import Data.Char
289import Data.Hashable (Hashable)
307import Data.Hashable (Hashable)
@@ -332,7 +350,7 @@ mkBHEnv s m = BHEnv s m return
332newtype BH m a = BH {
350newtype BH m a = BH {
333 unBH :: ReaderT BHEnv m a
351 unBH :: ReaderT BHEnv m a
334 } deriving ( Functor
352 } deriving ( Functor
335− , Applicative
353+ , A.Applicative
337 , MonadIO
355 , MonadIO
338 , MonadState s
356 , MonadState s
@@ -483,8 +501,31 @@ data ReplicaBounds = ReplicasBounded Int Int
483 | ReplicasUnbounded
501 | ReplicasUnbounded
484 deriving (Eq, Read, Show, Generic, Typeable)
502 deriving (Eq, Read, Show, Generic, Typeable)
504+-- | A measure of bytes used for various configurations. You may want
505+-- to use smart constructors like 'gigabytes' for larger values.
486newtype Bytes = Bytes Int deriving (Eq, Read, Show, Generic, Typeable, Ord, ToJSON, FromJSON)
515newtype Bytes = Bytes Int deriving (Eq, Read, Show, Generic, Typeable, Ord, ToJSON, FromJSON)
517+gigabytes :: Int -> Bytes
518+gigabytes n = megabytes (1000 * n)
521+megabytes :: Int -> Bytes
522+megabytes n = kilobytes (1000 * n)
525+kilobytes :: Int -> Bytes
526+kilobytes n = Bytes (1000 * n)
488data FSType = FSSimple
529data FSType = FSSimple
489 | FSBuffered deriving (Eq, Read, Show, Generic, Typeable, Ord)
530 | FSBuffered deriving (Eq, Read, Show, Generic, Typeable, Ord)
@@ -3625,3 +3666,149 @@ newtype EsUsername = EsUsername { esUsername :: Text } deriving (Read, Show, Eq)
3626-- | Password type used for HTTP Basic authentication. See 'basicAuthHook'.
3667-- | Password type used for HTTP Basic authentication. See 'basicAuthHook'.
3627newtype EsPassword = EsPassword { esPassword :: Text } deriving (Read, Show, Eq)
3668newtype EsPassword = EsPassword { esPassword :: Text } deriving (Read, Show, Eq)
3671+data SnapshotRepoSelection = SnapshotRepoList (NonEmpty SnapshotRepoPattern)
3672+ | AllSnapshotRepos deriving (Eq, Generic, Show, Typeable)
3675+-- | Either specifies an exact repo name or one with globs in it,
3676+-- e.g. @RepoPattern "foo*"@ __NOTE__: Patterns are not supported on ES < 1.7
3677+data SnapshotRepoPattern = ExactRepo SnapshotRepoName
3679+ deriving (Eq, Generic, Show, Typeable)
3681+-- | The unique name of a snapshot repository.
3682+newtype SnapshotRepoName = SnapshotRepoName { snapshotRepoName :: Text }
3683+ deriving (Eq, Generic, Show, Typeable, ToJSON, FromJSON)
3686+-- | A generic representation of a snapshot repo. This is what gets
3687+-- sent to and parsed from the server. For repo types enabled by
3688+-- plugins that aren't exported by this library, consider making a
3689+-- custom type which implements 'SnapshotRepo'. If it is a common repo
3690+-- type, consider submitting a pull request to have it included in the
3692+data GenericSnapshotRepo = GenericSnapshotRepo {
3693+ gSnapshotRepoName :: SnapshotRepoName
3694+ , gSnapshotRepoType :: SnapshotRepoType
3695+ , gSnapshotRepoSettings :: GenericSnapshotRepoSettings
3696+ } deriving (Eq, Generic, Show, Typeable)
3699+newtype SnapshotRepoType = SnapshotRepoType { snapshotRepoType :: Text }
3700+ deriving (Eq, Generic, Show, Typeable, ToJSON, FromJSON)
3703+-- | Opaque representation of snapshot repo settings. Instances of
3704+-- 'SnapshotRepo' will produce this.
3705+newtype GenericSnapshotRepoSettings = GenericSnapshotRepoSettings { gSnapshotRepoSettingsObject :: Object }
3706+ deriving (Eq, Generic, Show, Typeable, ToJSON, FromJSON)
3709+-- | The result of running 'verifySnapshotRepo'. --TODO: more detail once you know what a failure looks like
3710+newtype SnapshotVerification = SnapshotVerification { snapshotNodeVerifications :: [SnapshotNodeVerification] }
3711+ deriving (Eq, Generic, Show, Typeable)
3714+instance FromJSON SnapshotVerification where
3715+ parseJSON = withObject "SnapshotVerification" parse
3719+ SnapshotVerification <$> mapM (uncurry parse') (HM.toList o2)
3720+ parse' rawFullId = withObject "SnapshotNodeVerification" $ \o ->
3721+ SnapshotNodeVerification (FullNodeId rawFullId) <$> o .: "name"
3724+data SnapshotNodeVerification = SnapshotNodeVerification {
3725+ snvFullId :: FullNodeId
3726+ , snvNodeName :: NodeName
3727+ } deriving (Eq, Generic, Show, Typeable)
3730+-- | Unique, automatically-generated name assigned to nodes that are
3731+-- usually returned in node-oriented APIs.
3732+newtype FullNodeId = FullNodeId { fullNodeId :: Text }
3733+ deriving (Eq, Generic, Show, Typeable, FromJSON)
3736+newtype NodeName = NodeName { nodeName :: Text }
3737+ deriving (Eq, Generic, Show, Typeable, FromJSON)
3740+data SnapshotRepoUpdateSettings = SnapshotRepoUpdateSettings {
3741+ repoUpdateVerify :: Bool
3742+ -- ^ After creation/update, synchronously check that nodes can
3743+ -- write to this repo. Defaults to True. You may use False if you
3744+ -- need a faster response and plan on verifying manually later
3745+ -- with 'verifySnapshotRepo'.
3746+ } deriving (Eq, Show, Generic, Typeable)
3749+-- | Reasonable defaults for repo creation/update
3751+-- * repoUpdateVerify True
3752+defaultSnapshotRepoUpdateSettings :: SnapshotRepoUpdateSettings
3753+defaultSnapshotRepoUpdateSettings = SnapshotRepoUpdateSettings True
3756+-- | A filesystem-based snapshot repo that ships with elasticsearch.
3757+data FsSnapshotRepo = FsSnapshotRepo {
3758+ fsrName :: SnapshotRepoName
3759+ , fsrLocation :: FilePath
3760+ , fsrCompressMetadata :: Bool
3761+ , fsrChunkSize :: Maybe Bytes
3762+ , fsrMaxRestoreBytesPerSec :: Maybe Bytes
3763+ , fsrMaxSnapshotBytesPerSec :: Maybe Bytes
3764+ } deriving (Eq, Generic, Show, Typeable)
3767+instance SnapshotRepo FsSnapshotRepo where
3768+ toGSnapshotRepo FsSnapshotRepo {..} =
3769+ GenericSnapshotRepo fsrName fsRepoType (GenericSnapshotRepoSettings settings)
3771+ Object settings = object $ [ "location" .= fsrLocation
3772+ , "compress" .= fsrCompressMetadata
3774+ optionalPairs = catMaybes [ ("chunk_size" .=) <$> fsrChunkSize
3775+ , ("max_restore_bytes_per_sec" .=) <$> fsrMaxRestoreBytesPerSec
3776+ , ("max_snapshot_bytes_per_sec" .=) <$> fsrMaxSnapshotBytesPerSec
3778+ fromGSnapshotRepo GenericSnapshotRepo {..}
3779+ | gSnapshotRepoType == fsRepoType = do
3780+ let o = gSnapshotRepoSettingsObject gSnapshotRepoSettings
3782+ FsSnapshotRepo gSnapshotRepoName <$> o .: "location"
3783+ <*> o .:? "compress" .!= False
3784+ <*> o .:? "chunk_size"
3785+ <*> o .:? "max_restore_bytes_per_sec"
3786+ <*> o .:? "max_snapshot_bytes_per_sec"
3787+ | otherwise = Left (RepoTypeMismatch fsRepoType gSnapshotRepoType)
3790+--TODO: test what error case looks like
3791+parseRepo :: Parser a -> Either SnapshotRepoConversionError a
3792+parseRepo parser = case parseEither (const parser) () of
3793+ Left e -> Left (OtherRepoConversionError (T.pack e))
3797+fsRepoType :: SnapshotRepoType
3798+fsRepoType = SnapshotRepoType "fs"
3800+-- | Law: fromGSnapshotRepo (toGSnapshotRepo r) == Right r
3801+class SnapshotRepo r where
3802+ toGSnapshotRepo :: r -> GenericSnapshotRepo
3803+ fromGSnapshotRepo :: GenericSnapshotRepo -> Either SnapshotRepoConversionError r
3806+data SnapshotRepoConversionError = RepoTypeMismatch SnapshotRepoType
3810+ | OtherRepoConversionError Text
3811+ deriving (Show, Eq, Generic, Typeable)
3814+instance Exception SnapshotRepoConversionError