git.iko.soy/typeable/bloodhound
on master help sign in
WIP testing restore API
051a15eMichael Xavier
src/Database/Bloodhound/Client.hs+38−2
@@ -66,6 +66,7 @@ module Database.Bloodhound.Client
66 , createSnapshot
66 , createSnapshot
67 , getSnapshots
67 , getSnapshots
68 , deleteSnapshot
68 , deleteSnapshot
69+ , restoreSnapshot
69 , encodeBulkOperations
70 , encodeBulkOperations
70 , encodeBulkOperation
71 , encodeBulkOperation
71 -- * Authentication
72 -- * Authentication
@@ -361,7 +362,11 @@ createSnapshot (SnapshotRepoName repoName)
361 , Just ("ignore_global_state" .= snapIncludeGlobalState)
362 , Just ("ignore_global_state" .= snapIncludeGlobalState)
362 , Just ("partial" .= snapPartial)
363 , Just ("partial" .= snapPartial)
363 ]
364 ]
365+
366+
367+renderIndices :: NonEmpty IndexName -> Text
364− renderIndices (i :| is) = T.intercalate "," (renderIndex <$> (i:is))
368+renderIndices (i :| is) = T.intercalate "," (renderIndex <$> (i:is))
369+ where
365 renderIndex (IndexName n) = n
370 renderIndex (IndexName n) = n
366
371
367
372
@@ -400,6 +405,37 @@ deleteSnapshot (SnapshotRepoName repoName) (SnapshotName snapName) =
400 url = joinPath ["_snapshot", repoName, snapName]
405 url = joinPath ["_snapshot", repoName, snapName]
401
406
402
407
408+-- | Restore a snapshot to the cluster See
409+-- <https://www.elastic.co/guide/en/elasticsearch/reference/1.7/modules-snapshots.html#_restore>
410+-- for more details.
411+restoreSnapshot
412+ :: MonadBH m
413+ => SnapshotRepoName
414+ -> SnapshotName
415+ -> SnapshotRestoreSettings
416+ -- ^ Start with 'defaultSnapshotRestoreSettings' and customize
417+ -- from there for reasonable defaults.
418+ -> m Reply
419+restoreSnapshot (SnapshotRepoName repoName)
420+ (SnapshotName snapName)
421+ SnapshotRestoreSettings {..} = bindM2 put url (return (Just body))
422+ where
423+ url = addQuery params <$> joinPath ["_snapshot", repoName, snapName, "_restore"]
424+ params = [("wait_for_completion", Just (boolQP snapRestoreWaitForCompletion))]
425+ body = encode (object prs)
426+ prs = catMaybes [ ("indices" .=) . renderIndices <$> snapRestoreIndices
427+ , Just ("ignore_unavailable" .= snapRestoreIgnoreUnavailable)
428+ , Just ("include_global_state" .= snapRestoreIncludeGlobalState)
429+ , ("rename_pattern" .=) <$> snapRestoreRenamePattern
430+ , ("rename_replacement" .=) . renderTokens <$> snapRestoreRenameReplacement
431+ , Just ("include_aliases" .= snapRestoreIncludeAliases)
432+ ]
433+ renderTokens (t :| ts) = mconcat (renderToken <$> (t:ts))
434+ renderToken (RRTLit t) = t
435+ renderToken RRSubWholeMatch = "$0"
436+ renderToken (RRSubGroup g) = T.pack (show (rrGroupRefNum g))
437+
438+
403-- | 'createIndex' will create an index given a 'Server', 'IndexSettings', and an 'IndexName'.
439-- | 'createIndex' will create an index given a 'Server', 'IndexSettings', and an 'IndexName'.
404--
440--
405-- >>> response <- runBH' $ createIndex defaultIndexSettings (IndexName "didimakeanindex")
441-- >>> response <- runBH' $ createIndex defaultIndexSettings (IndexName "didimakeanindex")
@@ -484,7 +520,7 @@ optimizeIndex ixs IndexOptimizationSettings {..} =
484
520
485-------------------------------------------------------------------------------
521-------------------------------------------------------------------------------
486indexSelectionName :: IndexSelection -> Text
522indexSelectionName :: IndexSelection -> Text
487−indexSelectionName (IndexList names) = T.intercalate "," [n | IndexName n <- toList names]
523+indexSelectionName (IndexList names) = renderIndices names
488indexSelectionName AllIndexes = "_all"
524indexSelectionName AllIndexes = "_all"
489
525
490deepMerge :: [Object] -> Object
526deepMerge :: [Object] -> Object
src/Database/Bloodhound/Types.hs+111−8
@@ -260,6 +260,13 @@ module Database.Bloodhound.Types
260 , SnapshotInfo(..)
260 , SnapshotInfo(..)
261 , SnapshotName(..)
261 , SnapshotName(..)
262 , SnapshotState(..)
262 , SnapshotState(..)
263+ , SnapshotRestoreSettings(..)
264+ , defaultSnapshotRestoreSettings
265+ , RestoreRenamePattern(..)
266+ , RestoreRenameToken(..)
267+ , RRGroupRefNum
268+ , rrGroupRefNum
269+ , mkRRGroupRefNum
263
270
264 , Aggregation(..)
271 , Aggregation(..)
265 , Aggregations
272 , Aggregations
@@ -3831,23 +3838,23 @@ instance Exception SnapshotRepoConversionError
3831
3838
3832
3839
3833data SnapshotCreateSettings = SnapshotCreateSettings {
3840data SnapshotCreateSettings = SnapshotCreateSettings {
3834− snapWaitForCompletion :: Bool
3841+ snapWaitForCompletion :: Bool
3835 -- ^ Should the API call return immediately after initializing
3842 -- ^ Should the API call return immediately after initializing
3836− -- the snapshot or wait until completed. Note that if this is
3843+ -- the snapshot or wait until completed? Note that if this is
3837 -- enabled it could wait a long time, so you should adjust your
3844 -- enabled it could wait a long time, so you should adjust your
3838 -- 'ManagerSettings' accordingly to set long timeouts or
3845 -- 'ManagerSettings' accordingly to set long timeouts or
3839 -- explicitly handle timeouts.
3846 -- explicitly handle timeouts.
3840− , snapIndices :: Maybe (NonEmpty IndexName)
3847+ , snapIndices :: Maybe (NonEmpty IndexName)
3841 -- ^ Nothing will snapshot all indices. Just [] is permissable and
3848 -- ^ Nothing will snapshot all indices. Just [] is permissable and
3842 -- will essentially be a no-op snapshot.
3849 -- will essentially be a no-op snapshot.
3843− , snapIgnoreUnavailable :: Bool
3850+ , snapIgnoreUnavailable :: Bool
3844 -- ^ If set to True, any matched indices that don't exist will be
3851 -- ^ If set to True, any matched indices that don't exist will be
3845 -- ignored. Otherwise it will be an error and fail.
3852 -- ignored. Otherwise it will be an error and fail.
3846 , snapIncludeGlobalState :: Bool
3853 , snapIncludeGlobalState :: Bool
3847− , snapPartial :: Bool
3854+ , snapPartial :: Bool
3848 -- ^ If some indices failed to snapshot (e.g. if not all primary
3855 -- ^ If some indices failed to snapshot (e.g. if not all primary
3849 -- shards are available), should the process proceed?
3856 -- shards are available), should the process proceed?
3850− }
3857+ } deriving (Eq, Generic, Show, Typeable)
3851
3858
3852
3859
3853-- | Reasonable defaults for snapshot creation
3860-- | Reasonable defaults for snapshot creation
@@ -3858,8 +3865,13 @@ data SnapshotCreateSettings = SnapshotCreateSettings {
3858-- * snapIncludeGlobalState True
3865-- * snapIncludeGlobalState True
3859-- * snapPartial False
3866-- * snapPartial False
3860defaultSnapshotCreateSettings :: SnapshotCreateSettings
3867defaultSnapshotCreateSettings :: SnapshotCreateSettings
3861−defaultSnapshotCreateSettings =
3868+defaultSnapshotCreateSettings = SnapshotCreateSettings {
3862− SnapshotCreateSettings False Nothing False True False
3869+ snapWaitForCompletion = False
3870+ , snapIndices = Nothing
3871+ , snapIgnoreUnavailable = False
3872+ , snapIncludeGlobalState = True
3873+ , snapPartial = False
3874+ }
3863
3875
3864
3876
3865data SnapshotSelection = SnapshotList (NonEmpty SnapshotPattern)
3877data SnapshotSelection = SnapshotList (NonEmpty SnapshotPattern)
@@ -3938,3 +3950,94 @@ instance FromJSON SnapshotState where
3938
3950
3939newtype SnapshotName = SnapshotName { snapshotName :: Text }
3951newtype SnapshotName = SnapshotName { snapshotName :: Text }
3940 deriving (Show, Eq, Ord, Generic, Typeable, ToJSON, FromJSON)
3952 deriving (Show, Eq, Ord, Generic, Typeable, ToJSON, FromJSON)
3953+
3954+
3955+data SnapshotRestoreSettings = SnapshotRestoreSettings {
3956+ snapRestoreWaitForCompletion :: Bool
3957+ -- ^ Should the API call return immediately after initializing
3958+ -- the restore or wait until completed? Note that if this is
3959+ -- enabled, it could wait a long time, so you should adjust your
3960+ -- 'ManagerSettings' accordingly to set long timeouts or
3961+ -- explicitly handle timeouts.
3962+ , snapRestoreIndices :: Maybe (NonEmpty IndexName)
3963+ -- ^ Nothing will restore all indices in the snapshot. Just [] is
3964+ -- permissable and will essentially be a no-op restore.
3965+ , snapRestoreIgnoreUnavailable :: Bool
3966+ -- ^ If set to True, any indices that do not exist will be ignored
3967+ -- during snapshot rather than failing the restore.
3968+ , snapRestoreIncludeGlobalState :: Bool
3969+ -- ^ If set to false, will ignore any global state in the snapshot
3970+ -- and will not restore it.
3971+ , snapRestoreRenamePattern :: Maybe RestoreRenamePattern
3972+ -- ^ A regex pattern for matching indices. Used with
3973+ -- 'snapRestoreRenameReplacement', the restore can reference the
3974+ -- matched index and create a new index name upon restore.
3975+ , snapRestoreRenameReplacement :: Maybe (NonEmpty RestoreRenameToken)
3976+ -- ^ Expression of how index renames should be constructed.
3977+ , snapRestorePartial :: Bool
3978+ -- ^ If some indices fail to restore, should the process proceed?
3979+ , snapRestoreIncludeAliases :: Bool
3980+ -- ^ Should the restore also restore the aliases captured in the
3981+ -- snapshot.
3982+ } deriving (Eq, Generic, Show, Typeable)
3983+--TODO: temporary settings changes
3984+
3985+-- | Regex-stype pattern, e.g. "index_(.+)" to match index names
3986+newtype RestoreRenamePattern = RestoreRenamePattern { rrPattern :: Text }
3987+ deriving (Show, Eq, Generic, Typeable, Ord, ToJSON)
3988+
3989+
3990+-- | A single token in a index renaming scheme for a restore. These
3991+-- are concatenated into a string before being sent to
3992+-- ElasticSearch. Check out these Java
3993+-- <https://docs.oracle.com/javase/7/docs/api/java/util/regex/Matcher.html
3994+-- docs> to find out more if you're into that sort of thing.
3995+data RestoreRenameToken = RRTLit Text
3996+ -- ^ Just a literal string of characters
3997+ | RRSubWholeMatch
3998+ -- ^ Equivalent to $0. The entire matched pattern, not any subgroup
3999+ | RRSubGroup RRGroupRefNum
4000+ -- ^ A specific reference to a group number
4001+ deriving (Show, Eq, Generic, Typeable)
4002+
4003+
4004+-- | A group number for regex matching. Only values from 1-9 are
4005+-- supported. Construct with mkRRGroupRefNum
4006+newtype RRGroupRefNum = RRGroupRefNum { rrGroupRefNum :: Int }
4007+ deriving (Show, Eq, Generic, Typeable, Ord)
4008+
4009+instance Bounded RRGroupRefNum where
4010+ minBound = RRGroupRefNum 1
4011+ maxBound = RRGroupRefNum 9
4012+
4013+
4014+
4015+-- | Only allows valid group number references (0-9).
4016+mkRRGroupRefNum :: Int -> Maybe RRGroupRefNum
4017+mkRRGroupRefNum i
4018+ | i >= (rrGroupRefNum minBound) && i <= (rrGroupRefNum maxBound) =
4019+ Just $ RRGroupRefNum i
4020+ | otherwise = Nothing
4021+
4022+
4023+-- | Reasonable defaults for snapshot restores
4024+--
4025+-- * snapRestoreWaitForCompletion False
4026+-- * snapRestoreIndices Nothing
4027+-- * snapRestoreIgnoreUnavailable False
4028+-- * snapRestoreIncludeGlobalState True
4029+-- * snapRestoreRenamePattern Nothing
4030+-- * snapRestoreRenameReplacement Nothing
4031+-- * snapRestorePartial False
4032+-- * snapRestoreIncludeAliases True
4033+defaultSnapshotRestoreSettings :: SnapshotRestoreSettings
4034+defaultSnapshotRestoreSettings = SnapshotRestoreSettings {
4035+ snapRestoreWaitForCompletion = False
4036+ , snapRestoreIndices = Nothing
4037+ , snapRestoreIgnoreUnavailable = False
4038+ , snapRestoreIncludeGlobalState = True
4039+ , snapRestoreRenamePattern = Nothing
4040+ , snapRestoreRenameReplacement = Nothing
4041+ , snapRestorePartial = False
4042+ , snapRestoreIncludeAliases = True
4043+ }
tests/tests.hs+3
@@ -1487,6 +1487,9 @@ main = hspec $ do
1487 Right snaps -> expectationFailure ("Expected 1 snapshot but got" <> show (length snaps))
1487 Right snaps -> expectationFailure ("Expected 1 snapshot but got" <> show (length snaps))
1488 Left e -> expectationFailure (show e)
1488 Left e -> expectationFailure (show e)
1489
1489
1490+ describe "snapshot restore" $ do
1491+ it "can restore a snapshot that we create" pending
1492+
1490 describe "Enum DocVersion" $ do
1493 describe "Enum DocVersion" $ do
1491 it "follows the laws of Enum, Bounded" $ do
1494 it "follows the laws of Enum, Bounded" $ do
1492 evaluate (succ maxBound :: DocVersion) `shouldThrow` anyErrorCall
1495 evaluate (succ maxBound :: DocVersion) `shouldThrow` anyErrorCall