@@ -5,10 +5,10 @@
55{-# LANGUAGE GeneralizedNewtypeDeriving #-}
66{-# LANGUAGE MultiParamTypeClasses #-}
77-- {-# LANGUAGE NoMonomorphismRestriction #-}
8+{-# LANGUAGE NamedFieldPuns #-}
89{-# LANGUAGE OverloadedStrings #-}
910{-# LANGUAGE RecordWildCards #-}
1011{-# LANGUAGE UndecidableInstances #-}
11−{-# LANGUAGE NamedFieldPuns #-}
1212
1313-------------------------------------------------------------------------------
1414-- |
@@ -69,6 +69,9 @@ module Database.Bloodhound.Types
6969 , AllocationPolicy(..)
7070 , ReplicaBounds(..)
7171 , Bytes(..)
72+ , gigabytes
73+ , megabytes
74+ , kilobytes
7275 , FSType(..)
7376 , InitialShardCount(..)
7477 , NodeAttrFilter(..)
@@ -235,6 +238,38 @@ module Database.Bloodhound.Types
235238 , CollectionMode(..)
236239 , TermOrder(..)
237240 , TermInclusion(..)
241+ , SnapshotRepoSelection(..)
242+ , GenericSnapshotRepo(..)
243+ , SnapshotRepo(..)
244+ , SnapshotRepoConversionError(..)
245+ , SnapshotRepoType(..)
246+ , GenericSnapshotRepoSettings(..)
247+ , SnapshotRepoUpdateSettings(..)
248+ , defaultSnapshotRepoUpdateSettings
249+ , SnapshotRepoName(..)
250+ , SnapshotRepoPattern(..)
251+ , SnapshotVerification(..)
252+ , SnapshotNodeVerification(..)
253+ , FullNodeId(..)
254+ , NodeName(..)
255+ , FsSnapshotRepo(..)
256+ , SnapshotCreateSettings(..)
257+ , defaultSnapshotCreateSettings
258+ , SnapshotSelection(..)
259+ , SnapshotPattern(..)
260+ , SnapshotInfo(..)
261+ , SnapshotShardFailure(..)
262+ , ShardId(..)
263+ , SnapshotName(..)
264+ , SnapshotState(..)
265+ , SnapshotRestoreSettings(..)
266+ , defaultSnapshotRestoreSettings
267+ , RestoreRenamePattern(..)
268+ , RestoreRenameToken(..)
269+ , RRGroupRefNum
270+ , rrGroupRefNum
271+ , mkRRGroupRefNum
272+ , RestoreIndexSettings(..)
238273
239274 , Aggregation(..)
240275 , Aggregations
@@ -275,7 +310,7 @@ module Database.Bloodhound.Types
275310 , EsPassword(..)
276311 ) where
277312
278−import Control.Applicative
313+import Control.Applicative as A
279314import Control.Monad.Catch
280315import Control.Monad.Except
281316import Control.Monad.Reader
@@ -283,7 +318,7 @@ import Control.Monad.State
283318import Control.Monad.Writer
284319import Data.Aeson
285320import Data.Aeson.Types (Pair, Parser, emptyObject,
286− parseMaybe)
321+ parseEither, parseMaybe)
287322import qualified Data.ByteString.Lazy.Char8 as L
288323import Data.Char
289324import Data.Hashable (Hashable)
@@ -332,7 +367,7 @@ mkBHEnv s m = BHEnv s m return
332367newtype BH m a = BH {
333368 unBH :: ReaderT BHEnv m a
334369 } deriving ( Functor
335− , Applicative
370+ , A.Applicative
336371 , Monad
337372 , MonadIO
338373 , MonadState s
@@ -483,8 +518,31 @@ data ReplicaBounds = ReplicasBounded Int Int
483518 | ReplicasUnbounded
484519 deriving (Eq, Read, Show, Generic, Typeable)
485520
521+-- | A measure of bytes used for various configurations. You may want
522+-- to use smart constructors like 'gigabytes' for larger values.
523+--
524+-- >>> gigabytes 9
525+-- Bytes 9000000000
526+--
527+-- >>> megabytes 9
528+-- Bytes 9000000
529+--
530+-- >>> kilobytes 9
531+-- Bytes 9000
486532newtype Bytes = Bytes Int deriving (Eq, Read, Show, Generic, Typeable, Ord, ToJSON, FromJSON)
487533
534+gigabytes :: Int -> Bytes
535+gigabytes n = megabytes (1000 * n)
536+
537+
538+megabytes :: Int -> Bytes
539+megabytes n = kilobytes (1000 * n)
540+
541+
542+kilobytes :: Int -> Bytes
543+kilobytes n = Bytes (1000 * n)
544+
545+
488546data FSType = FSSimple
489547 | FSBuffered deriving (Eq, Read, Show, Generic, Typeable, Ord)
490548
@@ -803,6 +861,7 @@ newtype IndexName = IndexName Text deriving (Eq, Generic, Read, Show, ToJSON, Fr
803861{-| 'IndexSelection' is used for APIs which take a single index, a list of
804862 indexes, or the special @_all@ index.
805863-}
864+--TODO: this does not fully support <https://www.elastic.co/guide/en/elasticsearch/reference/1.7/multi-index.html multi-index syntax>. It wouldn't be too hard to implement but you'd have to add the optional parameters (ignore_unavailable, allow_no_indices, expand_wildcards) to any APIs using it. Also would be a breaking API.
806865data IndexSelection = IndexList (NonEmpty IndexName)
807866 | AllIndexes deriving (Eq, Generic, Show, Typeable)
808867
@@ -2947,7 +3006,7 @@ instance FromJSON UpdatableIndexSetting where
29473006 <|> blocksWrite `taggedAt` ["blocks", "write"]
29483007 <|> blocksMetaData `taggedAt` ["blocks", "metadata"]
29493008 where taggedAt f ks = taggedAt' f (Object o) ks
2950− taggedAt' f v [] = f =<< (parseJSON v <|> (parseJSON =<< unStringlyTypeJSON v))
3009+ taggedAt' f v [] = f =<< (parseJSON v <|> (parseJSON (unStringlyTypeJSON v)))
29513010 taggedAt' f v (k:ks) = withObject "Object" (\o -> do v' <- o .: k
29523011 taggedAt' f v' ks) v
29533012 numberOfReplicas = pure . NumberOfReplicas
@@ -2989,18 +3048,17 @@ instance FromJSON IndexSettingsSummary where
29893048 redundant (NumberOfReplicas _) = True
29903049 redundant _ = False
29913050
2992−-- | For some reason in the settings API, all leaf values get returned
3051+-- | For some reason in several settings APIs, all leaf values get returned
29933052-- as strings. This function attepmts to recover from this for all
2994−-- non-recursive JSON types. If nothing can be done or the same value
2995−-- would be return, it returns 'mzero'
2996−unStringlyTypeJSON :: MonadPlus m => Value -> m Value
2997−unStringlyTypeJSON (String "true") = return (Bool True)
2998−unStringlyTypeJSON (String "false") = return (Bool False)
2999−unStringlyTypeJSON (String "null") = return Null
3000−unStringlyTypeJSON (String t) = case readMay (T.unpack t) of
3001− Just n -> return (Number n)
3002− Nothing -> mzero
3003−unStringlyTypeJSON _ = mzero
3053+-- non-recursive JSON types. If nothing can be done, the value is left alone.
3054+unStringlyTypeJSON :: Value -> Value
3055+unStringlyTypeJSON (String "true") = Bool True
3056+unStringlyTypeJSON (String "false") = Bool False
3057+unStringlyTypeJSON (String "null") = Null
3058+unStringlyTypeJSON v@(String t) = case readMay (T.unpack t) of
3059+ Just n -> Number n
3060+ Nothing -> v
3061+unStringlyTypeJSON v = v
30043062
30053063
30063064parseSettings :: Object -> Parser [UpdatableIndexSetting]
@@ -3625,3 +3683,418 @@ newtype EsUsername = EsUsername { esUsername :: Text } deriving (Read, Show, Eq)
36253683
36263684-- | Password type used for HTTP Basic authentication. See 'basicAuthHook'.
36273685newtype EsPassword = EsPassword { esPassword :: Text } deriving (Read, Show, Eq)
3686+
3687+
3688+data SnapshotRepoSelection = SnapshotRepoList (NonEmpty SnapshotRepoPattern)
3689+ | AllSnapshotRepos deriving (Eq, Generic, Show, Typeable)
3690+
3691+
3692+-- | Either specifies an exact repo name or one with globs in it,
3693+-- e.g. @RepoPattern "foo*"@ __NOTE__: Patterns are not supported on ES < 1.7
3694+data SnapshotRepoPattern = ExactRepo SnapshotRepoName
3695+ | RepoPattern Text
3696+ deriving (Eq, Generic, Show, Typeable)
3697+
3698+-- | The unique name of a snapshot repository.
3699+newtype SnapshotRepoName = SnapshotRepoName { snapshotRepoName :: Text }
3700+ deriving (Eq, Ord, Generic, Show, Typeable, ToJSON, FromJSON)
3701+
3702+
3703+-- | A generic representation of a snapshot repo. This is what gets
3704+-- sent to and parsed from the server. For repo types enabled by
3705+-- plugins that aren't exported by this library, consider making a
3706+-- custom type which implements 'SnapshotRepo'. If it is a common repo
3707+-- type, consider submitting a pull request to have it included in the
3708+-- library proper
3709+data GenericSnapshotRepo = GenericSnapshotRepo {
3710+ gSnapshotRepoName :: SnapshotRepoName
3711+ , gSnapshotRepoType :: SnapshotRepoType
3712+ , gSnapshotRepoSettings :: GenericSnapshotRepoSettings
3713+ } deriving (Eq, Generic, Show, Typeable)
3714+
3715+
3716+instance SnapshotRepo GenericSnapshotRepo where
3717+ toGSnapshotRepo = id
3718+ fromGSnapshotRepo = Right
3719+
3720+
3721+newtype SnapshotRepoType = SnapshotRepoType { snapshotRepoType :: Text }
3722+ deriving (Eq, Ord, Generic, Show, Typeable, ToJSON, FromJSON)
3723+
3724+
3725+-- | Opaque representation of snapshot repo settings. Instances of
3726+-- 'SnapshotRepo' will produce this.
3727+newtype GenericSnapshotRepoSettings = GenericSnapshotRepoSettings { gSnapshotRepoSettingsObject :: Object }
3728+ deriving (Eq, Generic, Show, Typeable, ToJSON)
3729+
3730+
3731+ -- Regardless of whether you send strongly typed json, my version of
3732+ -- ES sends back stringly typed json in the settings, e.g. booleans
3733+ -- as strings, so we'll try to convert them.
3734+instance FromJSON GenericSnapshotRepoSettings where
3735+ parseJSON = fmap (GenericSnapshotRepoSettings . fmap unStringlyTypeJSON). parseJSON
3736+
3737+-- | The result of running 'verifySnapshotRepo'.
3738+newtype SnapshotVerification = SnapshotVerification { snapshotNodeVerifications :: [SnapshotNodeVerification] }
3739+ deriving (Eq, Generic, Show, Typeable)
3740+
3741+
3742+instance FromJSON SnapshotVerification where
3743+ parseJSON = withObject "SnapshotVerification" parse
3744+ where
3745+ parse o = do
3746+ o2 <- o .: "nodes"
3747+ SnapshotVerification <$> mapM (uncurry parse') (HM.toList o2)
3748+ parse' rawFullId = withObject "SnapshotNodeVerification" $ \o ->
3749+ SnapshotNodeVerification (FullNodeId rawFullId) <$> o .: "name"
3750+
3751+
3752+-- | A node that has verified a snapshot
3753+data SnapshotNodeVerification = SnapshotNodeVerification {
3754+ snvFullId :: FullNodeId
3755+ , snvNodeName :: NodeName
3756+ } deriving (Eq, Generic, Show, Typeable)
3757+
3758+
3759+-- | Unique, automatically-generated name assigned to nodes that are
3760+-- usually returned in node-oriented APIs.
3761+newtype FullNodeId = FullNodeId { fullNodeId :: Text }
3762+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
3763+
3764+
3765+-- | A human-readable node name that is supplied by the user in the
3766+-- node config or automatically generated by ElasticSearch.
3767+newtype NodeName = NodeName { nodeName :: Text }
3768+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
3769+
3770+
3771+data SnapshotRepoUpdateSettings = SnapshotRepoUpdateSettings {
3772+ repoUpdateVerify :: Bool
3773+ -- ^ After creation/update, synchronously check that nodes can
3774+ -- write to this repo. Defaults to True. You may use False if you
3775+ -- need a faster response and plan on verifying manually later
3776+ -- with 'verifySnapshotRepo'.
3777+ } deriving (Eq, Show, Generic, Typeable)
3778+
3779+
3780+-- | Reasonable defaults for repo creation/update
3781+--
3782+-- * repoUpdateVerify True
3783+defaultSnapshotRepoUpdateSettings :: SnapshotRepoUpdateSettings
3784+defaultSnapshotRepoUpdateSettings = SnapshotRepoUpdateSettings True
3785+
3786+
3787+-- | A filesystem-based snapshot repo that ships with
3788+-- ElasticSearch. This is an instance of 'SnapshotRepo' so it can be
3789+-- used with 'updateSnapshotRepo'
3790+data FsSnapshotRepo = FsSnapshotRepo {
3791+ fsrName :: SnapshotRepoName
3792+ , fsrLocation :: FilePath
3793+ , fsrCompressMetadata :: Bool
3794+ , fsrChunkSize :: Maybe Bytes
3795+ -- ^ Size by which to split large files during snapshotting.
3796+ , fsrMaxRestoreBytesPerSec :: Maybe Bytes
3797+ -- ^ Throttle node restore rate. If not supplied, defaults to 40mb/sec
3798+ , fsrMaxSnapshotBytesPerSec :: Maybe Bytes
3799+ -- ^ Throttle node snapshot rate. If not supplied, defaults to 40mb/sec
3800+ } deriving (Eq, Generic, Show, Typeable)
3801+
3802+
3803+instance SnapshotRepo FsSnapshotRepo where
3804+ toGSnapshotRepo FsSnapshotRepo {..} =
3805+ GenericSnapshotRepo fsrName fsRepoType (GenericSnapshotRepoSettings settings)
3806+ where
3807+ Object settings = object $ [ "location" .= fsrLocation
3808+ , "compress" .= fsrCompressMetadata
3809+ ] ++ optionalPairs
3810+ optionalPairs = catMaybes [ ("chunk_size" .=) <$> fsrChunkSize
3811+ , ("max_restore_bytes_per_sec" .=) <$> fsrMaxRestoreBytesPerSec
3812+ , ("max_snapshot_bytes_per_sec" .=) <$> fsrMaxSnapshotBytesPerSec
3813+ ]
3814+ fromGSnapshotRepo GenericSnapshotRepo {..}
3815+ | gSnapshotRepoType == fsRepoType = do
3816+ let o = gSnapshotRepoSettingsObject gSnapshotRepoSettings
3817+ parseRepo $ do
3818+ FsSnapshotRepo gSnapshotRepoName <$> o .: "location"
3819+ <*> o .:? "compress" .!= False
3820+ <*> o .:? "chunk_size"
3821+ <*> o .:? "max_restore_bytes_per_sec"
3822+ <*> o .:? "max_snapshot_bytes_per_sec"
3823+ | otherwise = Left (RepoTypeMismatch fsRepoType gSnapshotRepoType)
3824+
3825+
3826+parseRepo :: Parser a -> Either SnapshotRepoConversionError a
3827+parseRepo parser = case parseEither (const parser) () of
3828+ Left e -> Left (OtherRepoConversionError (T.pack e))
3829+ Right a -> Right a
3830+
3831+
3832+fsRepoType :: SnapshotRepoType
3833+fsRepoType = SnapshotRepoType "fs"
3834+
3835+-- | Law: fromGSnapshotRepo (toGSnapshotRepo r) == Right r
3836+class SnapshotRepo r where
3837+ toGSnapshotRepo :: r -> GenericSnapshotRepo
3838+ fromGSnapshotRepo :: GenericSnapshotRepo -> Either SnapshotRepoConversionError r
3839+
3840+
3841+data SnapshotRepoConversionError = RepoTypeMismatch SnapshotRepoType SnapshotRepoType
3842+ -- ^ Expected type and actual type
3843+ | OtherRepoConversionError Text
3844+ deriving (Show, Eq, Generic, Typeable)
3845+
3846+
3847+instance Exception SnapshotRepoConversionError
3848+
3849+
3850+data SnapshotCreateSettings = SnapshotCreateSettings {
3851+ snapWaitForCompletion :: Bool
3852+ -- ^ Should the API call return immediately after initializing
3853+ -- the snapshot or wait until completed? Note that if this is
3854+ -- enabled it could wait a long time, so you should adjust your
3855+ -- 'ManagerSettings' accordingly to set long timeouts or
3856+ -- explicitly handle timeouts.
3857+ , snapIndices :: Maybe IndexSelection
3858+ -- ^ Nothing will snapshot all indices. Just [] is permissable and
3859+ -- will essentially be a no-op snapshot.
3860+ , snapIgnoreUnavailable :: Bool
3861+ -- ^ If set to True, any matched indices that don't exist will be
3862+ -- ignored. Otherwise it will be an error and fail.
3863+ , snapIncludeGlobalState :: Bool
3864+ , snapPartial :: Bool
3865+ -- ^ If some indices failed to snapshot (e.g. if not all primary
3866+ -- shards are available), should the process proceed?
3867+ } deriving (Eq, Generic, Show, Typeable)
3868+
3869+
3870+-- | Reasonable defaults for snapshot creation
3871+--
3872+-- * snapWaitForCompletion False
3873+-- * snapIndices Nothing
3874+-- * snapIgnoreUnavailable False
3875+-- * snapIncludeGlobalState True
3876+-- * snapPartial False
3877+defaultSnapshotCreateSettings :: SnapshotCreateSettings
3878+defaultSnapshotCreateSettings = SnapshotCreateSettings {
3879+ snapWaitForCompletion = False
3880+ , snapIndices = Nothing
3881+ , snapIgnoreUnavailable = False
3882+ , snapIncludeGlobalState = True
3883+ , snapPartial = False
3884+ }
3885+
3886+
3887+data SnapshotSelection = SnapshotList (NonEmpty SnapshotPattern)
3888+ | AllSnapshots deriving (Eq, Generic, Show, Typeable)
3889+
3890+
3891+-- | Either specifies an exact snapshot name or one with globs in it,
3892+-- e.g. @SnapPattern "foo*"@ __NOTE__: Patterns are not supported on
3893+-- ES < 1.7
3894+data SnapshotPattern = ExactSnap SnapshotName
3895+ | SnapPattern Text
3896+ deriving (Eq, Generic, Show, Typeable)
3897+
3898+
3899+-- | General information about the state of a snapshot. Has some
3900+-- redundancies with 'SnapshotStatus'
3901+data SnapshotInfo = SnapshotInfo {
3902+ snapInfoShards :: ShardResult
3903+ , snapInfoFailures :: [SnapshotShardFailure]
3904+ , snapInfoDuration :: NominalDiffTime
3905+ , snapInfoEndTime :: UTCTime
3906+ , snapInfoStartTime :: UTCTime
3907+ , snapInfoState :: SnapshotState
3908+ , snapInfoIndices :: [IndexName]
3909+ , snapInfoName :: SnapshotName
3910+ } deriving (Eq, Generic, Show, Typeable)
3911+
3912+
3913+instance FromJSON SnapshotInfo where
3914+ parseJSON = withObject "SnapshotInfo" parse
3915+ where
3916+ parse o = SnapshotInfo <$> o .: "shards"
3917+ <*> o .: "failures"
3918+ <*> (unMS <$> o .: "duration_in_millis")
3919+ <*> (posixMS <$> o .: "end_time_in_millis")
3920+ <*> (posixMS <$> o .: "start_time_in_millis")
3921+ <*> o .: "state"
3922+ <*> o .: "indices"
3923+ <*> o .: "snapshot"
3924+
3925+data SnapshotShardFailure = SnapshotShardFailure {
3926+ snapShardFailureIndex :: IndexName
3927+ , snapShardFailureNodeId :: Maybe NodeName -- I'm not 100% sure this isn't actually 'FullNodeId'
3928+ , snapShardFailureReason :: Text
3929+ , snapShardFailureShardId :: ShardId
3930+ } deriving (Eq, Show, Generic, Typeable)
3931+
3932+
3933+instance FromJSON SnapshotShardFailure where
3934+ parseJSON = withObject "SnapshotShardFailure" parse
3935+ where
3936+ parse o = SnapshotShardFailure <$> o .: "index"
3937+ <*> o .:? "node_id"
3938+ <*> o .: "reason"
3939+ <*> o .: "shard_id"
3940+
3941+
3942+newtype ShardId = ShardId { shardId :: Int }
3943+ deriving (Eq, Show, Generic, Typeable, FromJSON)
3944+
3945+-- | Milliseconds
3946+newtype MS = MS NominalDiffTime
3947+
3948+
3949+-- keeps the unexported constructor warnings at bay
3950+unMS :: MS -> NominalDiffTime
3951+unMS (MS t) = t
3952+
3953+
3954+instance FromJSON MS where
3955+ parseJSON = withScientific "MS" (return . MS . parse)
3956+ where
3957+ parse n = fromInteger ((truncate n) * 1000)
3958+
3959+
3960+data SnapshotState = SnapshotInit
3961+ | SnapshotStarted
3962+ | SnapshotSuccess
3963+ | SnapshotFailed
3964+ | SnapshotAborted
3965+ | SnapshotMissing
3966+ | SnapshotWaiting
3967+ deriving (Show, Eq, Generic, Typeable)
3968+
3969+instance FromJSON SnapshotState where
3970+ parseJSON = withText "SnapshotState" parse
3971+ where
3972+ parse "INIT" = return SnapshotInit
3973+ parse "STARTED" = return SnapshotStarted
3974+ parse "SUCCESS" = return SnapshotSuccess
3975+ parse "FAILED" = return SnapshotFailed
3976+ parse "ABORTED" = return SnapshotAborted
3977+ parse "MISSING" = return SnapshotMissing
3978+ parse "WAITING" = return SnapshotWaiting
3979+ parse t = fail ("Invalid snapshot state " <> T.unpack t)
3980+
3981+
3982+newtype SnapshotName = SnapshotName { snapshotName :: Text }
3983+ deriving (Show, Eq, Ord, Generic, Typeable, ToJSON, FromJSON)
3984+
3985+
3986+data SnapshotRestoreSettings = SnapshotRestoreSettings {
3987+ snapRestoreWaitForCompletion :: Bool
3988+ -- ^ Should the API call return immediately after initializing
3989+ -- the restore or wait until completed? Note that if this is
3990+ -- enabled, it could wait a long time, so you should adjust your
3991+ -- 'ManagerSettings' accordingly to set long timeouts or
3992+ -- explicitly handle timeouts.
3993+ , snapRestoreIndices :: Maybe IndexSelection
3994+ -- ^ Nothing will restore all indices in the snapshot. Just [] is
3995+ -- permissable and will essentially be a no-op restore.
3996+ , snapRestoreIgnoreUnavailable :: Bool
3997+ -- ^ If set to True, any indices that do not exist will be ignored
3998+ -- during snapshot rather than failing the restore.
3999+ , snapRestoreIncludeGlobalState :: Bool
4000+ -- ^ If set to false, will ignore any global state in the snapshot
4001+ -- and will not restore it.
4002+ , snapRestoreRenamePattern :: Maybe RestoreRenamePattern
4003+ -- ^ A regex pattern for matching indices. Used with
4004+ -- 'snapRestoreRenameReplacement', the restore can reference the
4005+ -- matched index and create a new index name upon restore.
4006+ , snapRestoreRenameReplacement :: Maybe (NonEmpty RestoreRenameToken)
4007+ -- ^ Expression of how index renames should be constructed.
4008+ , snapRestorePartial :: Bool
4009+ -- ^ If some indices fail to restore, should the process proceed?
4010+ , snapRestoreIncludeAliases :: Bool
4011+ -- ^ Should the restore also restore the aliases captured in the
4012+ -- snapshot.
4013+ , snapRestoreIndexSettingsOverrides :: Maybe RestoreIndexSettings
4014+ -- ^ Settings to apply during the restore process. __NOTE:__ This
4015+ -- option is not supported in ES < 1.5 and should be set to
4016+ -- Nothing in that case.
4017+ , snapRestoreIgnoreIndexSettings :: Maybe (NonEmpty Text)
4018+ -- ^ This type could be more rich but it isn't clear which
4019+ -- settings are allowed to be ignored during restore, so we're
4020+ -- going with including this feature in a basic form rather than
4021+ -- omitting it. One example here would be
4022+ -- "index.refresh_interval". Any setting specified here will
4023+ -- revert back to the server default during the restore process.
4024+ } deriving (Eq, Generic, Show, Typeable)
4025+
4026+-- | Regex-stype pattern, e.g. "index_(.+)" to match index names
4027+newtype RestoreRenamePattern = RestoreRenamePattern { rrPattern :: Text }
4028+ deriving (Show, Eq, Generic, Typeable, Ord, ToJSON)
4029+
4030+
4031+-- | A single token in a index renaming scheme for a restore. These
4032+-- are concatenated into a string before being sent to
4033+-- ElasticSearch. Check out these Java
4034+-- <https://docs.oracle.com/javase/7/docs/api/java/util/regex/Matcher.html docs> to find out more if you're into that sort of thing.
4035+data RestoreRenameToken = RRTLit Text
4036+ -- ^ Just a literal string of characters
4037+ | RRSubWholeMatch
4038+ -- ^ Equivalent to $0. The entire matched pattern, not any subgroup
4039+ | RRSubGroup RRGroupRefNum
4040+ -- ^ A specific reference to a group number
4041+ deriving (Show, Eq, Generic, Typeable)
4042+
4043+
4044+-- | A group number for regex matching. Only values from 1-9 are
4045+-- supported. Construct with 'mkRRGroupRefNum'
4046+newtype RRGroupRefNum = RRGroupRefNum { rrGroupRefNum :: Int }
4047+ deriving (Show, Eq, Generic, Typeable, Ord)
4048+
4049+instance Bounded RRGroupRefNum where
4050+ minBound = RRGroupRefNum 1
4051+ maxBound = RRGroupRefNum 9
4052+
4053+
4054+-- | Only allows valid group number references (1-9).
4055+mkRRGroupRefNum :: Int -> Maybe RRGroupRefNum
4056+mkRRGroupRefNum i
4057+ | i >= (rrGroupRefNum minBound) && i <= (rrGroupRefNum maxBound) =
4058+ Just $ RRGroupRefNum i
4059+ | otherwise = Nothing
4060+
4061+
4062+-- | Reasonable defaults for snapshot restores
4063+--
4064+-- * snapRestoreWaitForCompletion False
4065+-- * snapRestoreIndices Nothing
4066+-- * snapRestoreIgnoreUnavailable False
4067+-- * snapRestoreIncludeGlobalState True
4068+-- * snapRestoreRenamePattern Nothing
4069+-- * snapRestoreRenameReplacement Nothing
4070+-- * snapRestorePartial False
4071+-- * snapRestoreIncludeAliases True
4072+-- * snapRestoreIndexSettingsOverrides Nothing
4073+-- * snapRestoreIgnoreIndexSettings Nothing
4074+defaultSnapshotRestoreSettings :: SnapshotRestoreSettings
4075+defaultSnapshotRestoreSettings = SnapshotRestoreSettings {
4076+ snapRestoreWaitForCompletion = False
4077+ , snapRestoreIndices = Nothing
4078+ , snapRestoreIgnoreUnavailable = False
4079+ , snapRestoreIncludeGlobalState = True
4080+ , snapRestoreRenamePattern = Nothing
4081+ , snapRestoreRenameReplacement = Nothing
4082+ , snapRestorePartial = False
4083+ , snapRestoreIncludeAliases = True
4084+ , snapRestoreIndexSettingsOverrides = Nothing
4085+ , snapRestoreIgnoreIndexSettings = Nothing
4086+ }
4087+
4088+
4089+-- | Index settings that can be overridden. The docs only mention you
4090+-- can update number of replicas, but there may be more. You
4091+-- definitely cannot override shard count.
4092+data RestoreIndexSettings = RestoreIndexSettings {
4093+ restoreOverrideReplicas :: Maybe ReplicaCount
4094+ } deriving (Show, Eq, Generic, Typeable)
4095+
4096+
4097+instance ToJSON RestoreIndexSettings where
4098+ toJSON RestoreIndexSettings {..} = object prs
4099+ where
4100+ prs = catMaybes [("index.number_of_replicas" .=) <$> restoreOverrideReplicas]