git.iko.soy/typeable/bloodhound
on master help sign in
Merge pull request #128 from Soostone/nodes-api

Nodes api

commit4f0f31deda8418c862ec7c82ca77c296a051fb32 authorChris Allen <cma@bitemyapp.com> dateSun 21 Aug 2016, 00:00 (10 years ago) parent947ad42ee24921
4 files changed+551−73
src/Database/Bloodhound/Client.hs+37−18 src/Database/Bloodhound/Types.hs+470−16 src/Database/Bloodhound/Types/Internal.hs+2−1 tests/tests.hs+42−38
src/Database/Bloodhound/Client.hs+37−18
@@ -77,6 +77,8 @@ module Database.Bloodhound.Client
7777 , deleteSnapshot
7878 -- *** Restoring Snapshots
7979 , restoreSnapshot
80+ -- ** Nodes
81+ , getNodesInfo
8082 -- ** Request Utilities
8183 , encodeBulkOperations
8284 , encodeBulkOperation
@@ -90,33 +92,32 @@ module Database.Bloodhound.Client
9092 )
9193 where
9294
93−import qualified Blaze.ByteString.Builder as BB
94−import Control.Applicative as A
95+import qualified Blaze.ByteString.Builder as BB
96+import Control.Applicative as A
9597import Control.Monad
9698import Control.Monad.Catch
9799import Control.Monad.IO.Class
98100import Data.Aeson
99101import Data.ByteString.Lazy.Builder
100−import qualified Data.ByteString.Lazy.Char8 as L
101−import Data.Foldable (toList)
102−import qualified Data.HashMap.Strict as HM
102+import qualified Data.ByteString.Lazy.Char8 as L
103+import Data.Foldable (toList)
104+import qualified Data.HashMap.Strict as HM
103105import Data.Ix
104−import qualified Data.List as LS (filter, foldl')
105−import Data.List.NonEmpty (NonEmpty (..))
106−import Data.Maybe (catMaybes, fromMaybe,
107− isJust)
106+import qualified Data.List as LS (filter, foldl')
107+import Data.List.NonEmpty (NonEmpty (..))
108+import Data.Maybe (catMaybes, fromMaybe, isJust)
108109import Data.Monoid
109−import Data.Text (Text)
110−import qualified Data.Text as T
111−import qualified Data.Text.Encoding as T
110+import Data.Text (Text)
111+import qualified Data.Text as T
112+import qualified Data.Text.Encoding as T
112113import Data.Time.Clock
113−import qualified Data.Vector as V
114+import qualified Data.Vector as V
114115import Network.HTTP.Client
115−import qualified Network.HTTP.Types.Method as NHTM
116−import qualified Network.HTTP.Types.Status as NHTS
117−import qualified Network.HTTP.Types.URI as NHTU
118−import qualified Network.URI as URI
119−import Prelude hiding (filter, head)
116+import qualified Network.HTTP.Types.Method as NHTM
117+import qualified Network.HTTP.Types.Status as NHTS
118+import qualified Network.HTTP.Types.URI as NHTU
119+import qualified Network.URI as URI
120+import Prelude hiding (filter, head)
120121
121122import Database.Bloodhound.Types
122123
@@ -456,6 +457,24 @@ restoreSnapshot (SnapshotRepoName repoName)
456457 renderToken (RRSubGroup g) = T.pack (show (rrGroupRefNum g))
457458
458459
460+getNodesInfo
461+ :: ( MonadBH m
462+ , MonadThrow m
463+ )
464+ => NodeSelection
465+ -> m (Either EsError NodesInfo)
466+getNodesInfo sel = parseEsResponse =<< get =<< url
467+ where
468+ url = joinPath ["_nodes", selectionSeg]
469+ selectionSeg = case sel of
470+ LocalNode -> "_local"
471+ NodeList (l :| ls) -> T.intercalate "," (selToSeg <$> (l:ls))
472+ AllNodes -> "_all"
473+ selToSeg (NodeByName (NodeName n)) = n
474+ selToSeg (NodeByFullNodeId (FullNodeId i)) = i
475+ selToSeg (NodeByHost (Server s)) = s
476+ selToSeg (NodeByAttribute (NodeAttrName a) v) = a <> ":" <> v
477+
459478-- | 'createIndex' will create an index given a 'Server', 'IndexSettings', and an 'IndexName'.
460479--
461480-- >>> response <- runBH' $ createIndex defaultIndexSettings (IndexName "didimakeanindex")
src/Database/Bloodhound/Types.hs+470−16
@@ -60,6 +60,8 @@ module Database.Bloodhound.Types
6060 , mkBHEnv
6161 , MonadBH(..)
6262 , Version(..)
63+ , VersionNumber(..)
64+ , BuildHash(..)
6365 , Status(..)
6466 , Existence(..)
6567 , NullValue(..)
@@ -146,6 +148,8 @@ module Database.Bloodhound.Types
146148 , Script(..)
147149 , IndexName(..)
148150 , IndexSelection(..)
151+ , NodeSelection(..)
152+ , NodeSelector(..)
149153 , IndexOptimizationSettings(..)
150154 , defaultIndexOptimizationSettings
151155 , TemplateName(..)
@@ -252,6 +256,31 @@ module Database.Bloodhound.Types
252256 , SnapshotNodeVerification(..)
253257 , FullNodeId(..)
254258 , NodeName(..)
259+ , ClusterName(..)
260+ , NodesInfo(..)
261+ , EsAddress(..)
262+ , PluginName(..)
263+ , NodeInfo(..)
264+ , NodePluginInfo(..)
265+ , NodeHTTPInfo(..)
266+ , NodeTransportInfo(..)
267+ , BoundTransportAddress(..)
268+ , NodeNetworkInfo(..)
269+ , MacAddress(..)
270+ , NetworkInterfaceName(..)
271+ , NodeNetworkInterface(..)
272+ , NodeThreadPoolsInfo(..)
273+ , NodeThreadPoolInfo(..)
274+ , ThreadPoolSize(..)
275+ , ThreadPoolType(..)
276+ , NodeJVMInfo(..)
277+ , JVMMemoryPool(..)
278+ , JVMGCCollector(..)
279+ , JVMMemoryInfo(..)
280+ , PID(..)
281+ , NodeOSInfo(..)
282+ , CPUInfo(..)
283+ , NodeProcessInfo(..)
255284 , FsSnapshotRepo(..)
256285 , SnapshotCreateSettings(..)
257286 , defaultSnapshotCreateSettings
@@ -311,6 +340,7 @@ module Database.Bloodhound.Types
311340 ) where
312341
313342import Control.Applicative as A
343+import Control.Arrow (first)
314344import Control.Monad.Catch
315345import Control.Monad.Except
316346import Control.Monad.Reader
@@ -323,7 +353,7 @@ import qualified Data.ByteString.Lazy.Char8 as L
323353import Data.Char
324354import Data.Hashable (Hashable)
325355import qualified Data.HashMap.Strict as HM
326−import Data.List (foldl', nub)
356+import Data.List (foldl', intercalate, nub)
327357import Data.List.NonEmpty (NonEmpty (..), toList)
328358import qualified Data.Map.Strict as M
329359import Data.Maybe
@@ -336,10 +366,12 @@ import Data.Time.Clock.POSIX
336366import qualified Data.Traversable as DT
337367import Data.Typeable (Typeable)
338368import qualified Data.Vector as V
369+import qualified Data.Version as Vers
339370import GHC.Enum
340371import GHC.Generics (Generic)
341372import Network.HTTP.Client
342373import qualified Network.HTTP.Types.Method as NHTM
374+import qualified Text.ParserCombinators.ReadP as RP
343375import qualified Text.Read as TR
344376
345377import Database.Bloodhound.Types.Class
@@ -395,11 +427,15 @@ runBH :: BHEnv -> BH m a -> m a
395427runBH e f = runReaderT (unBH f) e
396428
397429{-| 'Version' is embedded in 'Status' -}
398−data Version = Version { number :: Text
399− , build_hash :: Text
430+data Version = Version { number :: VersionNumber
431+ , build_hash :: BuildHash
400432 , build_timestamp :: UTCTime
401433 , build_snapshot :: Bool
402− , lucene_version :: Text } deriving (Eq, Read, Show, Generic, Typeable)
434+ , lucene_version :: VersionNumber } deriving (Eq, Read, Show, Generic, Typeable)
435+
436+-- | Traditional software versioning number
437+newtype VersionNumber = VersionNumber { versionNumber :: Vers.Version
438+ } deriving (Eq, Read, Show, Generic, Typeable, Ord)
403439
404440{-| 'Status' is a data type for describing the JSON body returned by
405441 Elasticsearch when you query its status. This was deprecated in 1.2.0.
@@ -865,6 +901,25 @@ newtype IndexName = IndexName Text deriving (Eq, Generic, Read, Show, ToJSON, Fr
865901data IndexSelection = IndexList (NonEmpty IndexName)
866902 | AllIndexes deriving (Eq, Generic, Show, Typeable)
867903
904+{-| 'NodeSelection' is used for most cluster APIs. See <https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster.html#cluster-nodes here> for more details.
905+-}
906+data NodeSelection = LocalNode
907+ -- ^ Whatever node receives this request
908+ | NodeList (NonEmpty NodeSelector)
909+ | AllNodes deriving (Eq, Generic, Show, Typeable)
910+
911+
912+-- | An exact match or pattern to identify a node. Note that All of
913+-- these options support wildcarding, so your node name, server, attr
914+-- name can all contain * characters to be a fuzzy match.
915+data NodeSelector = NodeByName NodeName
916+ | NodeByFullNodeId FullNodeId
917+ | NodeByHost Server
918+ -- ^ e.g. 10.0.0.1 or even 10.0.0.*
919+ | NodeByAttribute NodeAttrName Text
920+ -- ^ NodeAttrName can be a pattern, e.g. rack*. The value can too.
921+ deriving (Eq, Generic, Show, Typeable)
922+
868923{-| 'TemplateName' is used to describe which template to query/create/delete
869924-}
870925newtype TemplateName = TemplateName Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
@@ -1735,6 +1790,17 @@ instance FromJSON Version where
17351790 <*> o .: "build_snapshot"
17361791 <*> o .: "lucene_version"
17371792
1793+instance ToJSON VersionNumber where
1794+ toJSON = toJSON . Vers.showVersion . versionNumber
1795+
1796+instance FromJSON VersionNumber where
1797+ parseJSON = withText "VersionNumber" (parse . T.unpack)
1798+ where
1799+ parse s = case filter (null . snd)(RP.readP_to_S Vers.parseVersion s) of
1800+ [(v, _)] -> pure (VersionNumber v)
1801+ [] -> fail ("Invalid version string " ++ s)
1802+ xs -> fail ("Ambiguous version string " ++ s ++ " (" ++ intercalate ", " (Vers.showVersion . fst <$> xs) ++ ")")
1803+
17381804instance ToJSON TermOrder where
17391805 toJSON (TermOrder termSortField termSortOrder) = object [termSortField .= termSortOrder]
17401806
@@ -3767,6 +3833,189 @@ newtype FullNodeId = FullNodeId { fullNodeId :: Text }
37673833newtype NodeName = NodeName { nodeName :: Text }
37683834 deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
37693835
3836+newtype ClusterName = ClusterName { clusterName :: Text }
3837+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
3838+
3839+data NodesInfo = NodesInfo {
3840+ nodesInfo :: [NodeInfo]
3841+ , nodesClusterName :: ClusterName
3842+ } deriving (Eq, Show, Generic, Typeable)
3843+
3844+-- | A quirky address format used throughout ElasticSearch. An example
3845+-- would be inet[/1.1.1.1:9200]. inet may be a placeholder for a
3846+-- <https://en.wikipedia.org/wiki/Fully_qualified_domain_name FQDN>.
3847+newtype EsAddress = EsAddress { esAddress :: Text }
3848+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
3849+
3850+-- | Typically a 7 character hex string.
3851+newtype BuildHash = BuildHash { buildHash :: Text }
3852+ deriving (Eq, Ord, Generic, Read, Show, Typeable, FromJSON, ToJSON)
3853+
3854+newtype PluginName = PluginName { pluginName :: Text }
3855+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
3856+
3857+data NodeInfo = NodeInfo {
3858+ nodeInfoHTTPAddress :: EsAddress
3859+ , nodeInfoBuild :: BuildHash
3860+ , nodeInfoESVersion :: VersionNumber
3861+ , nodeInfoIP :: Server
3862+ , nodeInfoHost :: Server
3863+ , nodeInfoTransportAddress :: EsAddress
3864+ , nodeInfoName :: NodeName
3865+ , nodeInfoFullId :: FullNodeId
3866+ , nodeInfoPlugins :: [NodePluginInfo]
3867+ , nodeInfoHTTP :: NodeHTTPInfo
3868+ , nodeInfoTransport :: NodeTransportInfo
3869+ , nodeInfoNetwork :: NodeNetworkInfo
3870+ , nodeInfoThreadPool :: NodeThreadPoolsInfo
3871+ , nodeInfoJVM :: NodeJVMInfo
3872+ , nodeInfoProcess :: NodeProcessInfo
3873+ , nodeInfoOS :: NodeOSInfo
3874+ , nodeInfoSettings :: Object
3875+ -- ^ The members of the settings objects are not consistent,
3876+ -- dependent on plugins, etc.
3877+ } deriving (Eq, Show, Generic, Typeable)
3878+
3879+data NodePluginInfo = NodePluginInfo {
3880+ nodePluginSite :: Bool
3881+ -- ^ Is this a site plugin?
3882+ , nodePluginJVM :: Bool
3883+ -- ^ Is this plugin running on the JVM
3884+ , nodePluginDescription :: Text
3885+ , nodePluginVersion :: VersionNumber
3886+ , nodePluginName :: PluginName
3887+ } deriving (Eq, Show, Generic, Typeable)
3888+
3889+data NodeHTTPInfo = NodeHTTPInfo {
3890+ nodeHTTPMaxContentLength :: Bytes
3891+ , nodeHTTPTransportAddress :: BoundTransportAddress
3892+ } deriving (Eq, Show, Generic, Typeable)
3893+
3894+data NodeTransportInfo = NodeTransportInfo {
3895+ nodeTransportProfiles :: [BoundTransportAddress]
3896+ , nodeTransportAddress :: BoundTransportAddress
3897+ } deriving (Eq, Show, Generic, Typeable)
3898+
3899+data BoundTransportAddress = BoundTransportAddress {
3900+ publishAddress :: EsAddress
3901+ , boundAddress :: EsAddress
3902+ } deriving (Eq, Show, Generic, Typeable)
3903+
3904+data NodeNetworkInfo = NodeNetworkInfo {
3905+ nodeNetworkPrimaryInterface :: NodeNetworkInterface
3906+ , nodeNetworkRefreshInterval :: NominalDiffTime
3907+ } deriving (Eq, Show, Generic, Typeable)
3908+
3909+newtype MacAddress = MacAddress { macAddress :: Text }
3910+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
3911+
3912+newtype NetworkInterfaceName = NetworkInterfaceName { networkInterfaceName :: Text }
3913+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
3914+
3915+data NodeNetworkInterface = NodeNetworkInterface {
3916+ nodeNetIfaceMacAddress :: MacAddress
3917+ , nodeNetIfaceName :: NetworkInterfaceName
3918+ , nodeNetIfaceAddress :: Server
3919+ } deriving (Eq, Show, Generic, Typeable)
3920+
3921+data NodeThreadPoolsInfo = NodeThreadPoolsInfo {
3922+ nodeThreadPoolsRefresh :: NodeThreadPoolInfo
3923+ , nodeThreadPoolsManagement :: NodeThreadPoolInfo
3924+ , nodeThreadPoolsPercolate :: NodeThreadPoolInfo
3925+ , nodeThreadPoolsListener :: Maybe NodeThreadPoolInfo
3926+ , nodeThreadPoolsFetchShardStarted :: Maybe NodeThreadPoolInfo
3927+ , nodeThreadPoolsSearch :: NodeThreadPoolInfo
3928+ , nodeThreadPoolsFlush :: NodeThreadPoolInfo
3929+ , nodeThreadPoolsWarmer :: NodeThreadPoolInfo
3930+ , nodeThreadPoolsOptimize :: NodeThreadPoolInfo
3931+ , nodeThreadPoolsBulk :: NodeThreadPoolInfo
3932+ , nodeThreadPoolsSuggest :: NodeThreadPoolInfo
3933+ , nodeThreadPoolsMerge :: NodeThreadPoolInfo
3934+ , nodeThreadPoolsSnapshot :: NodeThreadPoolInfo
3935+ , nodeThreadPoolsGet :: NodeThreadPoolInfo
3936+ , nodeThreadPoolsFetchShardStore :: Maybe NodeThreadPoolInfo
3937+ , nodeThreadPoolsIndex :: NodeThreadPoolInfo
3938+ , nodeThreadPoolsGeneric :: NodeThreadPoolInfo
3939+ } deriving (Eq, Show, Generic, Typeable)
3940+
3941+data NodeThreadPoolInfo = NodeThreadPoolInfo {
3942+ nodeThreadPoolQueueSize :: ThreadPoolSize
3943+ , nodeThreadPoolKeepalive :: Maybe NominalDiffTime
3944+ , nodeThreadPoolMin :: Maybe Int
3945+ , nodeThreadPoolMax :: Maybe Int
3946+ , nodeThreadPoolType :: ThreadPoolType
3947+ } deriving (Eq, Show, Generic, Typeable)
3948+
3949+data ThreadPoolSize = ThreadPoolBounded Int
3950+ | ThreadPoolUnbounded
3951+ deriving (Eq, Show, Generic, Typeable)
3952+
3953+data ThreadPoolType = ThreadPoolScaling
3954+ | ThreadPoolFixed
3955+ | ThreadPoolCached
3956+ deriving (Eq, Show, Generic, Typeable)
3957+
3958+data NodeJVMInfo = NodeJVMInfo {
3959+ nodeJVMInfoMemoryPools :: [JVMMemoryPool]
3960+ , nodeJVMInfoMemoryPoolsGCCollectors :: [JVMGCCollector]
3961+ , nodeJVMInfoMemoryInfo :: JVMMemoryInfo
3962+ , nodeJVMInfoStartTime :: UTCTime
3963+ , nodeJVMInfoVMVendor :: Text
3964+ , nodeJVMVMVersion :: VersionNumber
3965+ -- ^ JVM doesn't seme to follow normal version conventions
3966+ , nodeJVMVMName :: Text
3967+ , nodeJVMVersion :: VersionNumber
3968+ , nodeJVMPID :: PID
3969+ } deriving (Eq, Show, Generic, Typeable)
3970+
3971+-- | Handles quirks in the way JVM versions are rendered (1.7.0_101 -> 1.7.0.101)
3972+newtype JVMVersion = JVMVersion { unJVMVersion :: VersionNumber }
3973+
3974+data JVMMemoryInfo = JVMMemoryInfo {
3975+ jvmMemoryInfoDirectMax :: Bytes
3976+ , jvmMemoryInfoNonHeapMax :: Bytes
3977+ , jvmMemoryInfoNonHeapInit :: Bytes
3978+ , jvmMemoryInfoHeapMax :: Bytes
3979+ , jvmMemoryInfoHeapInit :: Bytes
3980+ } deriving (Eq, Show, Generic, Typeable)
3981+
3982+newtype JVMMemoryPool = JVMMemoryPool {
3983+ jvmMemoryPool :: Text
3984+ } deriving (Eq, Show, Generic, Typeable, FromJSON)
3985+
3986+newtype JVMGCCollector = JVMGCCollector {
3987+ jvmGCCollector :: Text
3988+ } deriving (Eq, Show, Generic, Typeable, FromJSON)
3989+
3990+newtype PID = PID {
3991+ pid :: Int
3992+ } deriving (Eq, Show, Generic, Typeable, FromJSON)
3993+
3994+data NodeOSInfo = NodeOSInfo {
3995+ nodeOSSwap :: Bytes
3996+ , nodeOSMem :: Bytes
3997+ , nodeOSCPUInfo :: CPUInfo
3998+ , nodeOSAvailableProcessors :: Int
3999+ , nodeOSRefreshInterval :: NominalDiffTime
4000+ } deriving (Eq, Show, Generic, Typeable)
4001+
4002+data CPUInfo = CPUInfo {
4003+ cpuCacheSize :: Bytes
4004+ , cpuCoresPerSocket :: Int
4005+ , cpuTotalSockets :: Int
4006+ , cpuTotalCores :: Int
4007+ , cpuMHZ :: Int
4008+ , cpuModel :: Text
4009+ , cpuVendor :: Text
4010+ } deriving (Eq, Show, Generic, Typeable)
4011+
4012+data NodeProcessInfo = NodeProcessInfo {
4013+ nodeProcessMLockAll :: Bool
4014+ -- ^ See <https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-configuration.html>
4015+ , nodeProcessMaxFileDescriptors :: Int
4016+ , nodeProcessId :: PID
4017+ , nodeProcessRefreshInterval :: NominalDiffTime
4018+ } deriving (Eq, Show, Generic, Typeable)
37704019
37714020data SnapshotRepoUpdateSettings = SnapshotRepoUpdateSettings {
37724021 repoUpdateVerify :: Bool
@@ -3923,9 +4172,9 @@ instance FromJSON SnapshotInfo where
39234172 <*> o .: "snapshot"
39244173
39254174data SnapshotShardFailure = SnapshotShardFailure {
3926− snapShardFailureIndex :: IndexName
3927− , snapShardFailureNodeId :: Maybe NodeName -- I'm not 100% sure this isn't actually 'FullNodeId'
3928− , snapShardFailureReason :: Text
4175+ snapShardFailureIndex :: IndexName
4176+ , snapShardFailureNodeId :: Maybe NodeName -- I'm not 100% sure this isn't actually 'FullNodeId'
4177+ , snapShardFailureReason :: Text
39294178 , snapShardFailureShardId :: ShardId
39304179 } deriving (Eq, Show, Generic, Typeable)
39314180
@@ -3984,37 +4233,37 @@ newtype SnapshotName = SnapshotName { snapshotName :: Text }
39844233
39854234
39864235data SnapshotRestoreSettings = SnapshotRestoreSettings {
3987− snapRestoreWaitForCompletion :: Bool
4236+ snapRestoreWaitForCompletion :: Bool
39884237 -- ^ Should the API call return immediately after initializing
39894238 -- the restore or wait until completed? Note that if this is
39904239 -- enabled, it could wait a long time, so you should adjust your
39914240 -- 'ManagerSettings' accordingly to set long timeouts or
39924241 -- explicitly handle timeouts.
3993− , snapRestoreIndices :: Maybe IndexSelection
4242+ , snapRestoreIndices :: Maybe IndexSelection
39944243 -- ^ Nothing will restore all indices in the snapshot. Just [] is
39954244 -- permissable and will essentially be a no-op restore.
3996− , snapRestoreIgnoreUnavailable :: Bool
4245+ , snapRestoreIgnoreUnavailable :: Bool
39974246 -- ^ If set to True, any indices that do not exist will be ignored
39984247 -- during snapshot rather than failing the restore.
3999− , snapRestoreIncludeGlobalState :: Bool
4248+ , snapRestoreIncludeGlobalState :: Bool
40004249 -- ^ If set to false, will ignore any global state in the snapshot
40014250 -- and will not restore it.
4002− , snapRestoreRenamePattern :: Maybe RestoreRenamePattern
4251+ , snapRestoreRenamePattern :: Maybe RestoreRenamePattern
40034252 -- ^ A regex pattern for matching indices. Used with
40044253 -- 'snapRestoreRenameReplacement', the restore can reference the
40054254 -- matched index and create a new index name upon restore.
4006− , snapRestoreRenameReplacement :: Maybe (NonEmpty RestoreRenameToken)
4255+ , snapRestoreRenameReplacement :: Maybe (NonEmpty RestoreRenameToken)
40074256 -- ^ Expression of how index renames should be constructed.
4008− , snapRestorePartial :: Bool
4257+ , snapRestorePartial :: Bool
40094258 -- ^ If some indices fail to restore, should the process proceed?
4010− , snapRestoreIncludeAliases :: Bool
4259+ , snapRestoreIncludeAliases :: Bool
40114260 -- ^ Should the restore also restore the aliases captured in the
40124261 -- snapshot.
40134262 , snapRestoreIndexSettingsOverrides :: Maybe RestoreIndexSettings
40144263 -- ^ Settings to apply during the restore process. __NOTE:__ This
40154264 -- option is not supported in ES < 1.5 and should be set to
40164265 -- Nothing in that case.
4017− , snapRestoreIgnoreIndexSettings :: Maybe (NonEmpty Text)
4266+ , snapRestoreIgnoreIndexSettings :: Maybe (NonEmpty Text)
40184267 -- ^ This type could be more rich but it isn't clear which
40194268 -- settings are allowed to be ignored during restore, so we're
40204269 -- going with including this feature in a basic form rather than
@@ -4098,3 +4347,208 @@ instance ToJSON RestoreIndexSettings where
40984347 toJSON RestoreIndexSettings {..} = object prs
40994348 where
41004349 prs = catMaybes [("index.number_of_replicas" .=) <$> restoreOverrideReplicas]
4350+
4351+
4352+instance FromJSON NodesInfo where
4353+ parseJSON = withObject "NodesInfo" parse
4354+ where
4355+ parse o = do
4356+ nodes <- o .: "nodes"
4357+ infos <- forM (HM.toList nodes) $ \(fullNID, v) -> do
4358+ node <- parseJSON v
4359+ parseNodeInfo (FullNodeId fullNID) node
4360+ cn <- o .: "cluster_name"
4361+ return (NodesInfo infos cn)
4362+
4363+
4364+parseNodeInfo :: FullNodeId -> Object -> Parser NodeInfo
4365+parseNodeInfo nid o =
4366+ NodeInfo <$> o .: "http_address"
4367+ <*> o .: "build"
4368+ <*> o .: "version"
4369+ <*> o .: "ip"
4370+ <*> o .: "host"
4371+ <*> o .: "transport_address"
4372+ <*> o .: "name"
4373+ <*> pure nid
4374+ <*> o .: "plugins"
4375+ <*> o .: "http"
4376+ <*> o .: "transport"
4377+ <*> o .: "network"
4378+ <*> o .: "thread_pool"
4379+ <*> o .: "jvm"
4380+ <*> o .: "process"
4381+ <*> o .: "os"
4382+ <*> o .: "settings"
4383+
4384+instance FromJSON NodePluginInfo where
4385+ parseJSON = withObject "NodePluginInfo" parse
4386+ where
4387+ parse o = NodePluginInfo <$> o .: "site"
4388+ <*> o .: "jvm"
4389+ <*> o .: "description"
4390+ <*> o .: "version"
4391+ <*> o .: "name"
4392+
4393+instance FromJSON NodeHTTPInfo where
4394+ parseJSON = withObject "NodeHTTPInfo" parse
4395+ where
4396+ parse o = NodeHTTPInfo <$> o .: "max_content_length_in_bytes"
4397+ <*> parseJSON (Object o)
4398+
4399+instance FromJSON BoundTransportAddress where
4400+ parseJSON = withObject "BoundTransportAddress" parse
4401+ where
4402+ parse o = BoundTransportAddress <$> o .: "publish_address"
4403+ <*> o .: "bound_address"
4404+
4405+instance FromJSON NodeOSInfo where
4406+ parseJSON = withObject "NodeOSInfo" parse
4407+ where
4408+ parse o = do
4409+ swap <- o .: "swap"
4410+ mem <- o .: "mem"
4411+ NodeOSInfo <$> swap .: "total_in_bytes"
4412+ <*> mem .: "total_in_bytes"
4413+ <*> o .: "cpu"
4414+ <*> o .: "available_processors"
4415+ <*> (unMS <$> o .: "refresh_interval_in_millis")
4416+
4417+
4418+instance FromJSON CPUInfo where
4419+ parseJSON = withObject "CPUInfo" parse
4420+ where
4421+ parse o = CPUInfo <$> o .: "cache_size_in_bytes"
4422+ <*> o .: "cores_per_socket"
4423+ <*> o .: "total_sockets"
4424+ <*> o .: "total_cores"
4425+ <*> o .: "mhz"
4426+ <*> o .: "model"
4427+ <*> o .: "vendor"
4428+
4429+instance FromJSON NodeProcessInfo where
4430+ parseJSON = withObject "NodeProcessInfo" parse
4431+ where
4432+ parse o = NodeProcessInfo <$> o .: "mlockall"
4433+ <*> o .: "max_file_descriptors"
4434+ <*> o .: "id"
4435+ <*> (unMS <$> o .: "refresh_interval_in_millis")
4436+
4437+instance FromJSON NodeJVMInfo where
4438+ parseJSON = withObject "NodeJVMInfo" parse
4439+ where
4440+ parse o = NodeJVMInfo <$> o .: "memory_pools"
4441+ <*> o .: "gc_collectors"
4442+ <*> o .: "mem"
4443+ <*> (posixMS <$> o .: "start_time_in_millis")
4444+ <*> o .: "vm_vendor"
4445+ <*> o .: "vm_version"
4446+ <*> o .: "vm_name"
4447+ <*> (unJVMVersion <$> o .: "version")
4448+ <*> o .: "pid"
4449+
4450+instance FromJSON JVMVersion where
4451+ parseJSON (String t) =
4452+ JVMVersion <$> parseJSON (String (T.replace "_" "." t))
4453+ parseJSON v = JVMVersion <$> parseJSON v
4454+
4455+instance FromJSON JVMMemoryInfo where
4456+ parseJSON = withObject "JVMMemoryInfo" parse
4457+ where
4458+ parse o = JVMMemoryInfo <$> o .: "direct_max_in_bytes"
4459+ <*> o .: "non_heap_max_in_bytes"
4460+ <*> o .: "non_heap_init_in_bytes"
4461+ <*> o .: "heap_max_in_bytes"
4462+ <*> o .: "heap_init_in_bytes"
4463+
4464+instance FromJSON NodeThreadPoolsInfo where
4465+ parseJSON = withObject "NodeThreadPoolsInfo" parse
4466+ where
4467+ parse o = NodeThreadPoolsInfo <$> o .: "refresh"
4468+ <*> o .: "management"
4469+ <*> o .: "percolate"
4470+ <*> o .:? "listener"
4471+ <*> o .:? "fetch_shard_started"
4472+ <*> o .: "search"
4473+ <*> o .: "flush"
4474+ <*> o .: "warmer"
4475+ <*> o .: "optimize"
4476+ <*> o .: "bulk"
4477+ <*> o .: "suggest"
4478+ <*> o .: "merge"
4479+ <*> o .: "snapshot"
4480+ <*> o .: "get"
4481+ <*> o .:? "fetch_shard_store"
4482+ <*> o .: "index"
4483+ <*> o .: "generic"
4484+
4485+instance FromJSON NodeThreadPoolInfo where
4486+ parseJSON = withObject "NodeThreadPoolInfo" parse
4487+ where
4488+ parse o = do
4489+ ka <- maybe (return Nothing) (fmap Just . parseStringInterval) =<< o .:? "keep_alive"
4490+ NodeThreadPoolInfo <$> (parseJSON . unStringlyTypeJSON =<< o .: "queue_size")
4491+ <*> pure ka
4492+ <*> o .:? "min"
4493+ <*> o .:? "max"
4494+ <*> o .: "type"
4495+
4496+parseStringInterval :: (Monad m) => String -> m NominalDiffTime
4497+parseStringInterval s = case span isNumber s of
4498+ ("", _) -> fail "Invalid interval"
4499+ (nS, unitS) -> case (readMay nS, readMay unitS) of
4500+ (Just n, Just unit) -> return (fromInteger (n * unitNDT unit))
4501+ (Nothing, _) -> fail "Invalid interval number"
4502+ (_, Nothing) -> fail "Invalid interval unit"
4503+ where
4504+ unitNDT Seconds = 1
4505+ unitNDT Minutes = 60
4506+ unitNDT Hours = 60 * 60
4507+ unitNDT Days = 24 * 60 * 60
4508+ unitNDT Weeks = 7 * 24 * 60 * 60
4509+
4510+instance FromJSON ThreadPoolSize where
4511+ parseJSON v = parseAsNumber v <|> parseAsString v
4512+ where
4513+ parseAsNumber = parseAsInt <=< parseJSON
4514+ parseAsInt (-1) = return ThreadPoolUnbounded
4515+ parseAsInt n
4516+ | n >= 0 = return (ThreadPoolBounded n)
4517+ | otherwise = fail "Thread pool size must be >= -1."
4518+ parseAsString = withText "ThreadPoolSize" $ \t ->
4519+ case first (readMay . T.unpack) (T.span isNumber t) of
4520+ (Just n, "k") -> return (ThreadPoolBounded (n * 1000))
4521+ (Just n, "") -> return (ThreadPoolBounded n)
4522+ _ -> fail ("Invalid thread pool size " <> T.unpack t)
4523+
4524+instance FromJSON ThreadPoolType where
4525+ parseJSON = withText "ThreadPoolType" parse
4526+ where
4527+ parse "scaling" = return ThreadPoolScaling
4528+ parse "fixed" = return ThreadPoolFixed
4529+ parse "cached" = return ThreadPoolCached
4530+ parse e = fail ("Unexpected thread pool type" <> T.unpack e)
4531+
4532+instance FromJSON NodeTransportInfo where
4533+ parseJSON = withObject "NodeTransportInfo" parse
4534+ where
4535+ parse o = NodeTransportInfo <$> (maybe (return mempty) parseProfiles =<< o .:? "profiles")
4536+ <*> parseJSON (Object o)
4537+ parseProfiles (Object o) | HM.null o = return []
4538+ parseProfiles v@(Array _) = parseJSON v
4539+ parseProfiles Null = return []
4540+ parseProfiles _ = fail "Could not parse profiles"
4541+
4542+instance FromJSON NodeNetworkInfo where
4543+ parseJSON = withObject "NodeNetworkInfo" parse
4544+ where
4545+ parse o = NodeNetworkInfo <$> o .: "primary_interface"
4546+ <*> (unMS <$> o .: "refresh_interval_in_millis")
4547+
4548+
4549+instance FromJSON NodeNetworkInterface where
4550+ parseJSON = withObject "NodeNetworkInterface" parse
4551+ where
4552+ parse o = NodeNetworkInterface <$> o .: "mac_address"
4553+ <*> o .: "name"
4554+ <*> o .: "address"
src/Database/Bloodhound/Types/Internal.hs+2−1
@@ -24,6 +24,7 @@ module Database.Bloodhound.Types.Internal
2424
2525import Control.Applicative as A
2626import Control.Monad.Reader
27+import Data.Aeson
2728import Data.Text (Text)
2829import Data.Typeable (Typeable)
2930import GHC.Generics (Generic)
@@ -43,7 +44,7 @@ instance (Functor m, Applicative m, MonadIO m) => MonadBH (ReaderT BHEnv m) wher
4344
4445{-| 'Server' is used with the client functions to point at the ES instance
4546-}
46−newtype Server = Server Text deriving (Eq, Show, Generic, Typeable)
47+newtype Server = Server Text deriving (Eq, Show, Generic, Typeable, FromJSON)
4748
4849{-| All API calls to Elasticsearch operate within
4950 MonadBH
tests/tests.hs+42−38
@@ -36,6 +36,7 @@ import Data.Time.Clock (NominalDiffTime, UTCTime (..),
3636 secondsToDiffTime)
3737import Data.Typeable
3838import qualified Data.Vector as V
39+import qualified Data.Version as Vers
3940import Database.Bloodhound
4041import GHC.Generics as G
4142import Network.HTTP.Client hiding (Proxy)
@@ -76,42 +77,28 @@ createExampleIndex = createIndex (IndexSettings (ShardCount 1) (ReplicaCount 0))
7677deleteExampleIndex :: (MonadBH m) => m Reply
7778deleteExampleIndex = deleteIndex testIndex
7879
79−data ServerVersion = ServerVersion Int Int Int deriving (Show, Eq, Ord)
80+es13 :: Vers.Version
81+es13 = Vers.Version [1, 3, 0] []
8082
81−es13 :: ServerVersion
82−es13 = ServerVersion 1 3 0
83+es12 :: Vers.Version
84+es12 = Vers.Version [1, 2, 0] []
8385
84−es12 :: ServerVersion
85−es12 = ServerVersion 1 2 0
86+es11 :: Vers.Version
87+es11 = Vers.Version [1, 1, 0] []
8688
87−es11 :: ServerVersion
88−es11 = ServerVersion 1 1 0
89+es14 :: Vers.Version
90+es14 = Vers.Version [1, 4, 0] []
8991
90−es14 :: ServerVersion
91−es14 = ServerVersion 1 4 0
92+es15 :: Vers.Version
93+es15 = Vers.Version [1, 5, 0] []
9294
93−es15 :: ServerVersion
94−es15 = ServerVersion 1 5 0
95+es16 :: Vers.Version
96+es16 = Vers.Version [1, 6, 0] []
9597
96−es16 :: ServerVersion
97−es16 = ServerVersion 1 6 0
98−
99−serverBranch :: ServerVersion -> ServerVersion
100−serverBranch (ServerVersion majorVer minorVer patchVer) =
101− ServerVersion majorVer minorVer patchVer
102−
103−mkServerVersion :: [Int] -> Maybe ServerVersion
104−mkServerVersion [majorVer, minorVer, patchVer] =
105− Just (ServerVersion majorVer minorVer patchVer)
106−mkServerVersion _ = Nothing
107−
108−getServerVersion :: IO (Maybe ServerVersion)
109−getServerVersion = liftM extractVersion (withTestEnv getStatus)
98+getServerVersion :: IO (Maybe Vers.Version)
99+getServerVersion = fmap extractVersion <$> withTestEnv getStatus
110100 where
111− version' = T.splitOn "." . number . version
112− toInt = read . T.unpack
113− parseVersion v = map toInt (version' v)
114− extractVersion = join . liftM (mkServerVersion . parseVersion)
101+ extractVersion = versionNumber . number . version
115102
116103-- | Get configured repo paths for snapshotting. Note that by default
117104-- this is not enabled and if we are over es 1.5, we won't be able to
@@ -140,17 +127,14 @@ canSnapshot = do
140127 repoPaths <- getRepoPaths
141128 return (not caresAboutRepos || not (null (repoPaths)))
142129
143−testServerBranch :: IO (Maybe ServerVersion)
144−testServerBranch = getServerVersion >>= \v -> return $ liftM serverBranch v
130+atleast :: Vers.Version -> IO Bool
131+atleast v = getServerVersion >>= \x -> return $ x >= Just v
145132
146−atleast :: ServerVersion -> IO Bool
147−atleast v = testServerBranch >>= \x -> return $ x >= Just (serverBranch v)
133+atmost :: Vers.Version -> IO Bool
134+atmost v = getServerVersion >>= \x -> return $ x <= Just v
148135
149−atmost :: ServerVersion -> IO Bool
150−atmost v = testServerBranch >>= \x -> return $ x <= Just (serverBranch v)
151−
152−is :: ServerVersion -> IO Bool
153−is v = testServerBranch >>= \x -> return $ x == Just (serverBranch v)
136+is :: Vers.Version -> IO Bool
137+is v = getServerVersion >>= \x -> return $ x == Just v
154138
155139when' :: Monad m => m Bool -> m () -> m ()
156140when' b f = b >>= \x -> when x f
@@ -473,6 +457,7 @@ instance ApproxEq RegexpFlag
473457instance ApproxEq RegexpFlags
474458instance ApproxEq NullValue
475459instance ApproxEq Version
460+instance ApproxEq VersionNumber
476461instance ApproxEq DistanceRange
477462instance ApproxEq IndexName
478463instance ApproxEq MappingName
@@ -570,6 +555,8 @@ instance ApproxEq MultiMatchQuery
570555instance ApproxEq IndexSettings
571556instance ApproxEq AllocationPolicy
572557instance ApproxEq Char
558+instance ApproxEq Vers.Version where
559+ (=~) = (==)
573560instance ApproxEq a => ApproxEq [a] where
574561 as =~ bs = and (zipWith (=~) as bs)
575562instance (ApproxEq l, ApproxEq r) => ApproxEq (Either l r) where
@@ -578,6 +565,7 @@ instance (ApproxEq l, ApproxEq r) => ApproxEq (Either l r) where
578565 _ =~ _ = False
579566instance ApproxEq NodeAttrFilter
580567instance ApproxEq NodeAttrName
568+instance ApproxEq BuildHash
581569
582570-- | Due to the way nodeattrfilters get serialized here, they may come
583571-- out in a different order, but they are morally equivalent
@@ -767,10 +755,16 @@ instance Arbitrary NodeAttrFilter where
767755 let ts = T.pack <$> s :| ss
768756 return (NodeAttrFilter n ts)
769757
758+instance Arbitrary VersionNumber where
759+ arbitrary = mk . fmap getPositive . getNonEmpty <$> arbitrary
760+ where
761+ mk versions = VersionNumber (Vers.Version versions [])
762+
770763$(derive makeArbitrary ''IndexName)
771764$(derive makeArbitrary ''MappingName)
772765$(derive makeArbitrary ''DocId)
773766$(derive makeArbitrary ''Version)
767+$(derive makeArbitrary ''BuildHash)
774768$(derive makeArbitrary ''IndexAliasRouting)
775769$(derive makeArbitrary ''ShardCount)
776770$(derive makeArbitrary ''ReplicaCount)
@@ -1571,6 +1565,16 @@ main = hspec $ do
15711565 liftIO (exists `shouldBe` True)
15721566 go `finally` deleteIndex expectedIndex
15731567
1568+ describe "getNodesInfo" $ do
1569+ it "fetches the responding node when LocalNode is used" $ withTestEnv $ do
1570+ res <- getNodesInfo LocalNode
1571+ liftIO $ case res of
1572+ -- This is really just a smoke test for response
1573+ -- parsing. Node info is so variable, there's not much I can
1574+ -- assert here.
1575+ Right NodesInfo {..} -> length nodesInfo `shouldBe` 1
1576+ Left e -> expectationFailure ("Expected NodesInfo but got " <> show e)
1577+
15741578 describe "Enum DocVersion" $ do
15751579 it "follows the laws of Enum, Bounded" $ do
15761580 evaluate (succ maxBound :: DocVersion) `shouldThrow` anyErrorCall