-- | -- Module: PowerDNS.API.Servers -- Description: Servers endpoints for PowerDNS API -- -- This module implements the endpoints described at [Servers API](https://doc.powerdns.com/authoritative/http-api/server.html) {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE OverloadedStrings #-} module PowerDNS.API.Servers ( -- * API ServersAPI(..) -- * Data types , Server(..) , ObjectType(..) , SearchResult(..) , CacheFlushResult(..) , AnyStatisticItem(..) , StatisticItem(..) , MapStatisticItem(..) , RingStatisticItem(..) , SimpleStatisticItem(..) ) where import Data.Char (toLower) import Data.Data (Data) import Text.Read (readMaybe) import Control.DeepSeq (NFData) import Data.Aeson (FromJSON(..), ToJSON(..), defaultOptions , Value(String) , fieldLabelModifier, genericParseJSON , allNullaryToStringTag , genericToJSON , (.:), (.=) , withObject, object ) import Data.Aeson.Types (Parser) import qualified Data.Text as T import Servant.API import Servant.API.Generic import PowerDNS.Internal.Utils (Empty(..), strip) ---------------------------------------------------------------------------------------- type QueryParamReq = QueryParam' [Required, Strict] data ServersAPI f = ServersAPI { apiListServers :: f :- "servers" :> Get '[JSON] [Server] , apiGetServer :: f :- "servers" :> Capture "server_id" T.Text :> Get '[JSON] Server , apiSearch :: f :- "servers" :> Capture "server_id" T.Text :> "search-data" :> QueryParamReq "q" T.Text :> QueryParamReq "max" Integer :> QueryParam "object_type" ObjectType :> Get '[JSON] [SearchResult] , apiFlushCache :: f :- "servers" :> Capture "server_id" T.Text :> QueryParamReq "domain" T.Text :> Put '[JSON] CacheFlushResult , apiStatistics :: f :- "servers" :> Capture "server_id" T.Text :> "statistics" :> QueryParam "statistic" T.Text :> QueryParam "includerings" Bool :> Get '[JSON] [AnyStatisticItem] } deriving Generic ---------------------------------------------------------------------------------------- data Server = Server { server_type :: Maybe T.Text , server_id :: Maybe T.Text , server_daemon_type :: Maybe T.Text , server_version :: Maybe T.Text , server_url :: Maybe T.Text , server_config_url :: Maybe T.Text , server_zones_url :: Maybe T.Text } deriving (Eq, Ord, Show, Generic, NFData, Data, Empty) instance ToJSON Server where toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "server_"} instance FromJSON Server where parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "server_"} ---------------------------------------------------------------------------------------- data SearchResult = SearchResult { sr_content :: T.Text , sr_disabled :: Bool , sr_name :: T.Text , sr_object_type :: ObjectType , sr_zone_id :: T.Text , sr_zone :: T.Text , sr_type :: T.Text , sr_ttl :: Integer } deriving (Eq, Ord, Show, Generic, NFData, Data) instance ToJSON SearchResult where toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "sr_"} instance FromJSON SearchResult where parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "sr_"} ---------------------------------------------------------------------------------------- data ObjectType = TyAll | TyZone | TyRecord | TyComment deriving (Eq, Ord, Show, Generic, NFData, Data) instance ToJSON ObjectType where toJSON = genericToJSON defaultOptions { fieldLabelModifier = fmap toLower . strip "Ty" , allNullaryToStringTag = True } instance FromJSON ObjectType where parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = fmap toLower . strip "Ty" , allNullaryToStringTag = True } instance ToHttpApiData ObjectType where toQueryParam TyAll = "all" toQueryParam TyZone = "zone" toQueryParam TyRecord = "all" toQueryParam TyComment = "comment" ---------------------------------------------------------------------------------------- data CacheFlushResult = CacheFlushResult { cfr_count :: Integer , cfr_result :: T.Text } deriving (Eq, Ord, Show, Generic, NFData, Data) instance ToJSON CacheFlushResult where toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "cfr_"} instance FromJSON CacheFlushResult where parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "cfr_"} ---------------------------------------------------------------------------------------- data AnyStatisticItem = AnyStatisticItem StatisticItem | AnyMapStatisticItem MapStatisticItem | AnyRingStatisticItem RingStatisticItem deriving (Eq, Ord, Show, Generic, NFData, Data) instance ToJSON AnyStatisticItem where toJSON (AnyStatisticItem si) = object [ "type" .= String "StatisticItem" , "name" .= si_name si , "value" .= si_value si ] toJSON (AnyMapStatisticItem si) = object [ "type" .= String "MapStatisticItem" , "name" .= msi_name si , "value" .= msi_value si ] toJSON (AnyRingStatisticItem si) = object [ "type" .= String "RingStatisticItem" , "name" .= rsi_name si , "size" .= String (showT (rsi_size si)) , "value" .= rsi_value si ] showT :: Show a => a -> T.Text showT = T.pack . show thruRead :: Read a => T.Text -> Parser a thruRead = maybe (fail "failed to parse") pure . readMaybe . T.unpack instance FromJSON AnyStatisticItem where parseJSON = withObject "Any StatisticItem" $ \o -> do r <- o .: "type" case r of "StatisticItem" -> fmap AnyStatisticItem $ StatisticItem <$> o .: "name" <*> o .: "value" "MapStatisticItem" -> fmap AnyMapStatisticItem $ MapStatisticItem <$> o .: "name" <*> o .: "value" "RingStatisticItem" -> fmap AnyRingStatisticItem $ RingStatisticItem <$> o .: "name" <*> (o .: "size" >>= thruRead) <*> o .: "value" _ -> fail ("Unknown type: " <> T.unpack r) data StatisticItem = StatisticItem { si_name :: T.Text , si_value :: T.Text } deriving (Eq, Ord, Show, Generic, NFData, Data) data MapStatisticItem = MapStatisticItem { msi_name :: T.Text , msi_value :: [SimpleStatisticItem] } deriving (Eq, Ord, Show, Generic, NFData, Data) data RingStatisticItem = RingStatisticItem { rsi_name :: T.Text , rsi_size :: Integer , rsi_value :: [SimpleStatisticItem] } deriving (Eq, Ord, Show, Generic, NFData, Data) data SimpleStatisticItem = SimpleStatisticItem { ssi_name :: T.Text , ssi_value :: T.Text } deriving (Eq, Ord, Show, Generic, NFData, Data) instance ToJSON SimpleStatisticItem where toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "ssi_"} instance FromJSON SimpleStatisticItem where parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "ssi_"}