powerdns 0.4.1 → 0.4.2
raw patch · 11 files changed
+305/−330 lines, 11 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ PowerDNS.API.Zones: Result :: Text -> Result
+ PowerDNS.API.Zones: data Result
+ PowerDNS.API.Zones: instance Data.Aeson.Types.FromJSON.FromJSON PowerDNS.API.Zones.Result
+ PowerDNS.API.Zones: instance Data.Aeson.Types.ToJSON.ToJSON PowerDNS.API.Zones.Result
+ PowerDNS.Client: Result :: Text -> Result
+ PowerDNS.Client: data Result
- PowerDNS.API.Zones: ZonesAPI :: (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (QueryParam "zone" Text :> (QueryParam "dnssec" Bool :> Get '[JSON] [Zone])))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (QueryParam "rrset" Bool :> (ReqBody '[JSON] Zone :> PostCreated '[JSON] Zone)))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> (QueryParam "rrsets" Bool :> Get '[JSON] Zone)))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> DeleteNoContent))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> (ReqBody '[JSON] RRSets :> PatchNoContent)))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> (ReqBody '[JSON] Zone :> PutNoContent)))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> ("axfr-retrieve" :> Put '[JSON] NoContent)))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> ("notify" :> Put '[JSON] NoContent)))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> ("export" :> Get '[JSON] Text)))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> ("rectify" :> Put '[JSON] Text)))))) -> ZonesAPI f
+ PowerDNS.API.Zones: ZonesAPI :: (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (QueryParam "zone" Text :> (QueryParam "dnssec" Bool :> Get '[JSON] [Zone])))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (QueryParam "rrset" Bool :> (ReqBody '[JSON] Zone :> PostCreated '[JSON] Zone)))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> (QueryParam "rrsets" Bool :> Get '[JSON] Zone)))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> DeleteNoContent))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> (ReqBody '[JSON] RRSets :> PatchNoContent)))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> (ReqBody '[JSON] Zone :> PutNoContent)))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> ("axfr-retrieve" :> Put '[JSON] Result)))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> ("notify" :> Put '[JSON] Result)))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> ("export" :> Get '[JSON] Result)))))) -> (f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> ("rectify" :> Put '[JSON] Result)))))) -> ZonesAPI f
- PowerDNS.API.Zones: [apiGetZoneAxfr] :: ZonesAPI f -> f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> ("export" :> Get '[JSON] Text)))))
+ PowerDNS.API.Zones: [apiGetZoneAxfr] :: ZonesAPI f -> f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> ("export" :> Get '[JSON] Result)))))
- PowerDNS.API.Zones: [apiNotifySlaves] :: ZonesAPI f -> f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> ("notify" :> Put '[JSON] NoContent)))))
+ PowerDNS.API.Zones: [apiNotifySlaves] :: ZonesAPI f -> f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> ("notify" :> Put '[JSON] Result)))))
- PowerDNS.API.Zones: [apiRectifyZone] :: ZonesAPI f -> f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> ("rectify" :> Put '[JSON] Text)))))
+ PowerDNS.API.Zones: [apiRectifyZone] :: ZonesAPI f -> f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> ("rectify" :> Put '[JSON] Result)))))
- PowerDNS.API.Zones: [apiTriggerAxfr] :: ZonesAPI f -> f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> ("axfr-retrieve" :> Put '[JSON] NoContent)))))
+ PowerDNS.API.Zones: [apiTriggerAxfr] :: ZonesAPI f -> f :- ("servers" :> (Capture "server_id" Text :> ("zones" :> (Capture "zone_id" Text :> ("axfr-retrieve" :> Put '[JSON] Result)))))
- PowerDNS.Client: getZoneAxfr :: Text -> Text -> ClientM Text
+ PowerDNS.Client: getZoneAxfr :: Text -> Text -> ClientM Result
- PowerDNS.Client: notifySlaves :: Text -> Text -> ClientM NoContent
+ PowerDNS.Client: notifySlaves :: Text -> Text -> ClientM Result
- PowerDNS.Client: rectifyZone :: Text -> Text -> ClientM Text
+ PowerDNS.Client: rectifyZone :: Text -> Text -> ClientM Result
- PowerDNS.Client: triggerAxfr :: Text -> Text -> ClientM NoContent
+ PowerDNS.Client: triggerAxfr :: Text -> Text -> ClientM Result
Files
- CHANGELOG.md +15/−0
- PowerDNS/API.hs +11/−13
- PowerDNS/API/Cryptokeys.hs +5/−8
- PowerDNS/API/Metadata.hs +5/−9
- PowerDNS/API/Servers.hs +55/−73
- PowerDNS/API/TSIGKeys.hs +23/−26
- PowerDNS/API/Version.hs +3/−7
- PowerDNS/API/Zones.hs +172/−185
- PowerDNS/Client.hs +5/−4
- powerdns.cabal +5/−5
- spec/Spec.hs +6/−0
CHANGELOG.md view
@@ -34,3 +34,18 @@ ## 0.4.1 -- 2022-04-22 * Relax various constraints++## 0.4.1 -- 2022-04-22++* Add new datatype Result+* Fix the following endpoints to produce 'Result' rather than NoContent+ * apiTriggerAxfr+ * apiNotifySlaves+ * apiGetZoneAxfr+ * apiRectifyZone+* Fix the following client functions similarly:+ * triggerAxfr+ * notifySlaves+ * getZoneAxfr+ * rectifyZone+* Improve compilation time by switching to TH for JSON instances
PowerDNS/API.hs view
@@ -4,9 +4,9 @@ -- -- This module exports a complete servant API description of the PowerDNS. May be useful to some. -{-# LANGUAGE DataKinds #-}-{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE TypeOperators #-} module PowerDNS.API ( API , api@@ -20,18 +20,17 @@ ) where -import GHC.Generics (Generic)-import Data.Proxy (Proxy(..))+import Data.Proxy (Proxy(..))+import GHC.Generics (Generic) -import Servant.API-import Servant.API.Generic ((:-), ToServantApi)+import Servant.API -import PowerDNS.API.Version-import PowerDNS.API.Zones-import PowerDNS.API.Servers-import PowerDNS.API.Cryptokeys-import PowerDNS.API.Metadata-import PowerDNS.API.TSIGKeys+import PowerDNS.API.Cryptokeys+import PowerDNS.API.Metadata+import PowerDNS.API.Servers+import PowerDNS.API.TSIGKeys+import PowerDNS.API.Version+import PowerDNS.API.Zones api :: Proxy API api = Proxy@@ -46,4 +45,3 @@ , metadata :: f :- "api" :> "v1" :> ToServantApi MetadataAPI , tsigkeys :: f :- "api" :> "v1" :> ToServantApi TSIGKeysAPI } deriving Generic-
PowerDNS/API/Cryptokeys.hs view
@@ -9,6 +9,7 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TemplateHaskell #-} module PowerDNS.API.Cryptokeys ( -- * API@@ -22,9 +23,9 @@ import Data.Data (Data) import Control.DeepSeq (NFData)-import Data.Aeson (FromJSON(..), ToJSON(..), defaultOptions,- fieldLabelModifier, genericParseJSON,- genericToJSON)+import Data.Aeson.TH (defaultOptions,+ fieldLabelModifier,+ deriveJSON) import qualified Data.Text as T import Servant.API import Servant.API.Generic@@ -66,8 +67,4 @@ , ck_bits :: Maybe Integer } deriving (Eq, Ord, Show, Generic, NFData, Data, Empty) -instance ToJSON Cryptokey where- toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "ck_"}--instance FromJSON Cryptokey where- parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "ck_"}+$(deriveJSON defaultOptions { fieldLabelModifier = strip "ck_"} ''Cryptokey)
PowerDNS/API/Metadata.hs view
@@ -9,6 +9,7 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TemplateHaskell #-} module PowerDNS.API.Metadata ( -- * API@@ -20,10 +21,9 @@ where import Control.DeepSeq (NFData)-import Data.Aeson ( FromJSON(..), ToJSON(..)- , defaultOptions, fieldLabelModifier- , genericParseJSON, genericToJSON- )+import Data.Aeson.TH ( defaultOptions, fieldLabelModifier+ , deriveJSON+ ) import Data.Data (Data) import qualified Data.Text as T@@ -56,8 +56,4 @@ , md_metadata :: [T.Text] } deriving (Eq, Ord, Show, Generic, NFData, Data) -instance ToJSON Metadata where- toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "md_"}--instance FromJSON Metadata where- parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "md_"}+$(deriveJSON defaultOptions { fieldLabelModifier = strip "md_" } ''Metadata)
PowerDNS/API/Servers.hs view
@@ -6,6 +6,7 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TypeOperators #-}@@ -34,13 +35,12 @@ import Text.Read (readMaybe) import Control.DeepSeq (NFData)-import Data.Aeson (FromJSON(..), ToJSON(..), defaultOptions- , Value(String)+import Data.Aeson.TH (defaultOptions , fieldLabelModifier, constructorTagModifier- , genericParseJSON+ , deriveJSON , allNullaryToStringTag- , genericToJSON- , (.:), (.=)+ )+import Data.Aeson (FromJSON(..), ToJSON(..), Value(String), (.:), (.=) , withObject, object ) import Data.Aeson.Types (Parser)@@ -52,32 +52,6 @@ ---------------------------------------------------------------------------------------- -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@@ -88,45 +62,18 @@ , 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_"}+$(deriveJSON defaultOptions { fieldLabelModifier = strip "server_" } ''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 { constructorTagModifier = map1 toLower . strip "Ty"- , allNullaryToStringTag = True }--instance FromJSON ObjectType where- parseJSON = genericParseJSON defaultOptions { constructorTagModifier = map1 toLower . strip "Ty"- , allNullaryToStringTag = True }+$(deriveJSON defaultOptions { constructorTagModifier = map1 toLower . strip "Ty"+ , allNullaryToStringTag = True } ''ObjectType) instance FromHttpApiData ObjectType where parseQueryParam "all" = Right TyAll@@ -143,17 +90,37 @@ ---------------------------------------------------------------------------------------- +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)++$(deriveJSON defaultOptions { fieldLabelModifier = strip "sr_" } ''SearchResult)++----------------------------------------------------------------------------------------+ 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_"}+$(deriveJSON defaultOptions { fieldLabelModifier = strip "cfr_" } ''CacheFlushResult) -instance FromJSON CacheFlushResult where- parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "cfr_"}+---------------------------------------------------------------------------------------- +data SimpleStatisticItem = SimpleStatisticItem+ { ssi_name :: T.Text+ , ssi_value :: T.Text+ } deriving (Eq, Ord, Show, Generic, NFData, Data)++$(deriveJSON defaultOptions { fieldLabelModifier = strip "ssi_" } ''SimpleStatisticItem)+ ---------------------------------------------------------------------------------------- data AnyStatisticItem = AnyStatisticItem StatisticItem@@ -211,13 +178,28 @@ , 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_"}+type QueryParamReq = QueryParam' [Required, Strict]+data ServersAPI f = ServersAPI+ { apiListServers :: f :- "servers"+ :> Get '[JSON] [Server] -instance FromJSON SimpleStatisticItem where- parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "ssi_"}+ , 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
PowerDNS/API/TSIGKeys.hs view
@@ -12,6 +12,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TemplateHaskell #-} module PowerDNS.API.TSIGKeys ( -- * API@@ -30,9 +31,10 @@ import Control.DeepSeq (NFData) import Data.Aeson (FromJSON(..), ToJSON(..), Value(String),- allNullaryToStringTag, constructorTagModifier,- defaultOptions, genericParseJSON, genericToJSON, object, withObject, (.:), (.:?), (.=))++import Data.Aeson.TH (allNullaryToStringTag, constructorTagModifier,+ defaultOptions, deriveJSON) import qualified Data.ByteString as BS import qualified Data.ByteString.Base64 as BS64 import qualified Data.Text as T@@ -71,6 +73,25 @@ -- ^ Unlike the original PowerDNS API we do not require the key to be base64 encoded. } deriving (Eq, Ord, Show, Generic, NFData, Data) +----------------------------------------------------------------------------------------++-- | Supported algorithms according to [PowerDNS TSIG Documentation](https://doc.powerdns.com/authoritative/tsig.html#tsig)+data TSIGAlgorithm = HMAC_MD5+ | HMAC_SHA1+ | HMAC_SHA224+ | HMAC_SHA256+ | HMAC_SHA384+ | HMAC_SHA512+ deriving (Eq, Ord, Show, Generic, NFData, Data)++$(deriveJSON defaultOptions { allNullaryToStringTag = True+ , constructorTagModifier = fmap $ \c ->+ if c == '_' then '-' else toLower c+ } ''TSIGAlgorithm)+++----------------------------------------------------------------------------------------+ instance ToJSON TSIGKey where toJSON key = object [ "name" .= tsk_name key , "id" .= tsk_id key@@ -94,27 +115,3 @@ decode64 i = case BS64.decode (T.encodeUtf8 i) of Left err -> Fail.fail err Right k -> pure k---------------------------------------------------------------------------------------------- | Supported algorithms according to [PowerDNS TSIG Documentation](https://doc.powerdns.com/authoritative/tsig.html#tsig)-data TSIGAlgorithm = HMAC_MD5- | HMAC_SHA1- | HMAC_SHA224- | HMAC_SHA256- | HMAC_SHA384- | HMAC_SHA512- deriving (Eq, Ord, Show, Generic, NFData, Data)--instance ToJSON TSIGAlgorithm where- toJSON = genericToJSON defaultOptions { allNullaryToStringTag = True- , constructorTagModifier = algo- }--instance FromJSON TSIGAlgorithm where- parseJSON = genericParseJSON defaultOptions { allNullaryToStringTag = True- , constructorTagModifier = algo- }--algo :: String -> String-algo = fmap (\c -> if c == '_' then '-' else toLower c)
PowerDNS/API/Version.hs view
@@ -9,6 +9,7 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TemplateHaskell #-} module PowerDNS.API.Version ( -- * API@@ -22,8 +23,7 @@ import Data.Data (Data) import Control.DeepSeq (NFData)-import Data.Aeson (FromJSON(..), ToJSON(..), defaultOptions, fieldLabelModifier,- genericParseJSON, genericToJSON)+import Data.Aeson.TH (defaultOptions, fieldLabelModifier, deriveJSON) import qualified Data.Text as T import Servant.API@@ -40,9 +40,5 @@ , version_url :: T.Text } deriving (Eq, Ord, Show, Generic, NFData, Data) -instance ToJSON Version where- toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "version_" }--instance FromJSON Version where- parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "version_" }+$(deriveJSON defaultOptions { fieldLabelModifier = strip "version_" } ''Version)
PowerDNS/API/Zones.hs view
@@ -9,6 +9,8 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TypeOperators #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-} module PowerDNS.API.Zones ( -- * API@@ -26,6 +28,7 @@ -- * Utilities , CIText+ , Result(..) , mkCIText , original , caseFolded@@ -41,10 +44,11 @@ import Text.Read (readPrec) import Control.DeepSeq (NFData(..), deepseq)-import Data.Aeson (FromJSON(..), ToJSON(..), allNullaryToStringTag,- constructorTagModifier, defaultOptions,- fieldLabelModifier, genericParseJSON,- genericToJSON, omitNothingFields)+import Data.Aeson.TH (allNullaryToStringTag,+ constructorTagModifier, defaultOptions,+ fieldLabelModifier,+ deriveJSON, omitNothingFields)+import Data.Aeson (FromJSON(..), ToJSON(..), object, (.:), (.=), withObject) import Data.Hashable (Hashable(..)) import qualified Data.Text as T import Data.Time.Clock.POSIX (POSIXTime)@@ -55,114 +59,106 @@ ---------------------------------------------------------------------------------------- -data ZonesAPI f = ZonesAPI- { apiListZones :: f :- "servers" :> Capture "server_id" T.Text :> "zones"- :> QueryParam "zone" T.Text- :> QueryParam "dnssec" Bool- :> Get '[JSON] [Zone]-- , apiCreateZone :: f :- "servers" :> Capture "server_id" T.Text :> "zones"- :> QueryParam "rrset" Bool- :> ReqBody '[JSON] Zone- :> PostCreated '[JSON] Zone-- , apiGetZone :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text- :> QueryParam "rrsets" Bool- :> Get '[JSON] Zone-- , apiDeleteZone :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text- :> DeleteNoContent-- , apiUpdateRecords :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text- :> ReqBody '[JSON] RRSets- :> PatchNoContent-- , apiUpdateZone :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text- :> ReqBody '[JSON] Zone- :> PutNoContent-- , apiTriggerAxfr :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text :> "axfr-retrieve"- :> Put '[JSON] NoContent-- , apiNotifySlaves :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text :> "notify"- :> Put '[JSON] NoContent-- , apiGetZoneAxfr :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text :> "export"- :> Get '[JSON] T.Text-- , apiRectifyZone :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text :> "rectify"- :> Put '[JSON] T.Text+-- | Record according to [PowerDNS Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#record)+data Record = Record+ { record_content :: T.Text+ , record_disabled :: Bool+ } deriving (Eq, Ord, Show, Generic, NFData, Data) - } deriving Generic+$(deriveJSON defaultOptions { fieldLabelModifier = strip "record_"+ , omitNothingFields = True } ''Record) ---------------------------------------------------------------------------------------- --- | Zone according to [PowerDNS Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#zone).--- All fields are optional because the PowerDNS API differs on which fields are required depending on the endpoint.------ Note that 'Eq' and 'Ord' use limited case-sensitivity on 'zone_name' and equivalently contained rrset names--- as per [RFC4343](https://datatracker.ietf.org/doc/html/rfc4343)-data Zone = Zone- { zone_id :: Maybe T.Text- , zone_name :: Maybe CIText- , zone_type :: Maybe T.Text- , zone_url :: Maybe T.Text- , zone_kind :: Maybe Kind- , zone_rrsets :: Maybe [RRSet]- , zone_serial :: Maybe Integer- , zone_notified_serial :: Maybe Integer- , zone_edited_serial :: Maybe Integer- , zone_masters :: Maybe [T.Text]- , zone_dnssec :: Maybe Bool- , zone_nsec3param :: Maybe T.Text- , zone_nsec3narrow :: Maybe Bool- , zone_presigned :: Maybe Bool- , zone_soa_edit :: Maybe T.Text- , zone_soa_edit_api :: Maybe T.Text- , zone_api_rectify :: Maybe Bool- , zone_zone :: Maybe T.Text- , zone_account :: Maybe T.Text- , zone_nameservers :: Maybe [T.Text]- , zone_master_tsig_key_ids :: Maybe [T.Text]- , zone_slave_tsig_key_ids :: Maybe [T.Text]+-- | Comment according to [PowerDNS Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#comment)+data Comment = Comment+ { comment_content :: Maybe T.Text+ , comment_account :: Maybe T.Text+ , comment_modified_at :: Maybe POSIXTime } deriving (Eq, Ord, Show, Generic, NFData, Data, Empty) -instance ToJSON Zone where- toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "zone_"}--instance FromJSON Zone where- parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "zone_"}+$(deriveJSON defaultOptions { fieldLabelModifier = strip "comment_" } ''Comment) ---------------------------------------------------------------------------------------- -data Kind = Native | Master | Slave- deriving (Eq, Ord, Show, Generic, NFData, Data)+-- | Whether or not an 'RRSet' replace or delete an existing entry.+-- If the 'ChangeType' is left at @Nothing@ it will create a new domain entry.+data ChangeType = Replace+ | Delete+ deriving (Eq, Ord, Show, Generic, NFData, Data) -instance ToJSON Kind where- toJSON = genericToJSON defaultOptions { allNullaryToStringTag = True }+$(deriveJSON defaultOptions { constructorTagModifier = fmap toUpper+ , allNullaryToStringTag = True } ''ChangeType) -instance FromJSON Kind where- parseJSON = genericParseJSON defaultOptions { allNullaryToStringTag = True } + ---------------------------------------------------------------------------------------- --- | A list of RRSets-data RRSets = RRSets- { rrsets :: [RRSet]- } deriving (Eq, Ord, Show, Generic, NFData, Data)+data RecordType = A+ | AAAA+ | AFSDB+ | ALIAS+ | APL+ | CAA+ | CERT+ | CDNSKEY+ | CDS+ | CNAME+ | DNSKEY+ | DNAME+ | DS+ | HINFO+ | KEY+ | LOC+ | MX+ | NAPTR+ | NS+ | NSEC+ | NSEC3+ | NSEC3PARAM+ | OPENPGPKEY+ | PTR+ | RP+ | RRSIG+ | SOA+ | SPF+ | SSHFP+ | SRV+ | TKEY+ | TSIG+ | TLSA+ | SMIMEA+ | TXT+ | URI+ | A6+ | DHCID+ | DLV+ | EUI48+ | EUI64+ | IPSECKEY+ | KX+ | MAILA+ | MAILB+ | MINFO+ | MR+ | RKEY+ | SIG+ | WKS+ deriving (Eq, Ord, Show, Generic, NFData, Data) -instance ToJSON RRSets-instance FromJSON RRSets+$(deriveJSON defaultOptions { allNullaryToStringTag = True+ } ''RecordType) + ---------------------------------------------------------------------------------------- -- | A wrapper for 'T.Text' implementing limited case-sensitivity as per [RFC4343](https://datatracker.ietf.org/doc/html/rfc4343). -- Use 'mkCIText' for construction. -- -- See 'original' and 'caseFolded' for extracting a 'T.Text' back.-data CIText = CIText { ciOriginal :: T.Text, ciCaseFolded :: T.Text } deriving Data +data CIText = CIText { ciOriginal :: T.Text, ciCaseFolded :: T.Text } deriving Data -- | Obtain the original 'T.Text' from a 'CIText'. original :: CIText -> T.Text@@ -219,6 +215,8 @@ | otherwise = x +----------------------------------------------------------------------------------------+ -- | RRSet according to [PowerDNS Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#rrset). -- -- Note that 'Eq' and 'Ord' use limited case-sensitivity on 'rrset_name' as per [RFC4343](https://datatracker.ietf.org/doc/html/rfc4343)@@ -231,118 +229,107 @@ , rrset_comments :: Maybe [Comment] } deriving (Eq, Ord, Show, Generic, NFData, Data) -instance ToJSON RRSet where- toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "rrset_"- , omitNothingFields = True }+$(deriveJSON defaultOptions { fieldLabelModifier = strip "rrset_"+ , omitNothingFields = True } ''RRSet) -instance FromJSON RRSet where- parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "rrset_"- , omitNothingFields = True }+---------------------------------------------------------------------------------------- +-- | A list of RRSets+data RRSets = RRSets+ { rrsets :: [RRSet]+ } deriving (Eq, Ord, Show, Generic, NFData, Data)++instance ToJSON RRSets+instance FromJSON RRSets+ ---------------------------------------------------------------------------------------- -data RecordType = A- | AAAA- | AFSDB- | ALIAS- | APL- | CAA- | CERT- | CDNSKEY- | CDS- | CNAME- | DNSKEY- | DNAME- | DS- | HINFO- | KEY- | LOC- | MX- | NAPTR- | NS- | NSEC- | NSEC3- | NSEC3PARAM- | OPENPGPKEY- | PTR- | RP- | RRSIG- | SOA- | SPF- | SSHFP- | SRV- | TKEY- | TSIG- | TLSA- | SMIMEA- | TXT- | URI- | A6- | DHCID- | DLV- | EUI48- | EUI64- | IPSECKEY- | KX- | MAILA- | MAILB- | MINFO- | MR- | RKEY- | SIG- | WKS- deriving (Eq, Ord, Show, Generic, NFData, Data)+data Kind = Native | Master | Slave+ deriving (Eq, Ord, Show, Generic, NFData, Data) -instance ToJSON RecordType where- toJSON = genericToJSON defaultOptions { allNullaryToStringTag = True- }+$(deriveJSON defaultOptions { allNullaryToStringTag = True } ''Kind) -instance FromJSON RecordType where- parseJSON = genericParseJSON defaultOptions { allNullaryToStringTag = True- }+---------------------------------------------------------------------------------------- +-- | Zone according to [PowerDNS Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#zone).+-- All fields are optional because the PowerDNS API differs on which fields are required depending on the endpoint.+--+-- Note that 'Eq' and 'Ord' use limited case-sensitivity on 'zone_name' and equivalently contained rrset names+-- as per [RFC4343](https://datatracker.ietf.org/doc/html/rfc4343)+data Zone = Zone+ { zone_id :: Maybe T.Text+ , zone_name :: Maybe CIText+ , zone_type :: Maybe T.Text+ , zone_url :: Maybe T.Text+ , zone_kind :: Maybe Kind+ , zone_rrsets :: Maybe [RRSet]+ , zone_serial :: Maybe Integer+ , zone_notified_serial :: Maybe Integer+ , zone_edited_serial :: Maybe Integer+ , zone_masters :: Maybe [T.Text]+ , zone_dnssec :: Maybe Bool+ , zone_nsec3param :: Maybe T.Text+ , zone_nsec3narrow :: Maybe Bool+ , zone_presigned :: Maybe Bool+ , zone_soa_edit :: Maybe T.Text+ , zone_soa_edit_api :: Maybe T.Text+ , zone_api_rectify :: Maybe Bool+ , zone_zone :: Maybe T.Text+ , zone_account :: Maybe T.Text+ , zone_nameservers :: Maybe [T.Text]+ , zone_master_tsig_key_ids :: Maybe [T.Text]+ , zone_slave_tsig_key_ids :: Maybe [T.Text]+ } deriving (Eq, Ord, Show, Generic, NFData, Data, Empty)++$(deriveJSON defaultOptions { fieldLabelModifier = strip "zone_" } ''Zone)+ ---------------------------------------------------------------------------------------- --- | Whether or not an 'RRSet' replace or delete an existing entry.--- If the 'ChangeType' is left at @Nothing@ it will create a new domain entry.-data ChangeType = Replace- | Delete- deriving (Eq, Ord, Show, Generic, NFData, Data)+data ZonesAPI f = ZonesAPI+ { apiListZones :: f :- "servers" :> Capture "server_id" T.Text :> "zones"+ :> QueryParam "zone" T.Text+ :> QueryParam "dnssec" Bool+ :> Get '[JSON] [Zone] -instance ToJSON ChangeType where- toJSON = genericToJSON defaultOptions { constructorTagModifier = fmap toUpper- , allNullaryToStringTag = True }+ , apiCreateZone :: f :- "servers" :> Capture "server_id" T.Text :> "zones"+ :> QueryParam "rrset" Bool+ :> ReqBody '[JSON] Zone+ :> PostCreated '[JSON] Zone -instance FromJSON ChangeType where- parseJSON = genericParseJSON defaultOptions { constructorTagModifier = fmap toUpper- , allNullaryToStringTag = True }+ , apiGetZone :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text+ :> QueryParam "rrsets" Bool+ :> Get '[JSON] Zone -------------------------------------------------------------------------------------------- | Record according to [PowerDNS Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#record)-data Record = Record- { record_content :: T.Text- , record_disabled :: Bool- } deriving (Eq, Ord, Show, Generic, NFData, Data)+ , apiDeleteZone :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text+ :> DeleteNoContent -instance ToJSON Record where- toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "record_"- , omitNothingFields = True }+ , apiUpdateRecords :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text+ :> ReqBody '[JSON] RRSets+ :> PatchNoContent -instance FromJSON Record where- parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "record_"- , omitNothingFields = True }+ , apiUpdateZone :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text+ :> ReqBody '[JSON] Zone+ :> PutNoContent -----------------------------------------------------------------------------------------+ , apiTriggerAxfr :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text :> "axfr-retrieve"+ :> Put '[JSON] Result --- | Comment according to [PowerDNS Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#comment)-data Comment = Comment- { comment_content :: Maybe T.Text- , comment_account :: Maybe T.Text- , comment_modified_at :: Maybe POSIXTime- } deriving (Eq, Ord, Show, Generic, NFData, Data, Empty)+ , apiNotifySlaves :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text :> "notify"+ :> Put '[JSON] Result -instance ToJSON Comment where- toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "comment_" }+ , apiGetZoneAxfr :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text :> "export"+ :> Get '[JSON] Result -instance FromJSON Comment where- parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "comment_" }+ , apiRectifyZone :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text :> "rectify"+ :> Put '[JSON] Result++ } deriving Generic+++data Result = Result T.Text++instance ToJSON Result where+ toJSON (Result t) = object ["result" .= t]++instance FromJSON Result where+ parseJSON = withObject "result" $ \o -> Result <$> (o .: "result")
PowerDNS/Client.hs view
@@ -52,6 +52,7 @@ , Comment(..) , ChangeType(..) , RecordType(..)+ , Result(..) -- * Cryptokeys -- | See documentation at [PowerDNS Cryptokeys API](https://doc.powerdns.com/authoritative/http-api/cryptokey.html)@@ -208,25 +209,25 @@ -- | Trigger zone transfer on a slave. See [Zones API Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#put--servers-server_id-zones-zone_id-axfr-retrieve) triggerAxfr :: T.Text -- ^ Server name -> T.Text -- ^ Zone ID- -> ClientM NoContent+ -> ClientM Result triggerAxfr = apiTriggerAxfr zonesClient -- | Send DNS notify to slaves. See [Zones API Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#put--servers-server_id-zones-zone_id-notify) notifySlaves :: T.Text -- ^ Server name -> T.Text -- ^ Zone ID- -> ClientM NoContent+ -> ClientM Result notifySlaves = apiNotifySlaves zonesClient -- | Return zone in AXFR format. See [Zones API Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#get--servers-server_id-zones-zone_id-export) getZoneAxfr :: T.Text -- ^ Server name -> T.Text -- ^ Zone ID- -> ClientM T.Text -- ^ Zone in AXFR format+ -> ClientM Result -- ^ Zone in AXFR format getZoneAxfr = apiGetZoneAxfr zonesClient -- | Rectify the zone data. See [Zones API Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#put--servers-server_id-zones-zone_id-rectify) rectifyZone :: T.Text -- ^ Server name -> T.Text -- ^ Zone ID- -> ClientM T.Text+ -> ClientM Result rectifyZone = apiRectifyZone zonesClient ----------------------------------------------------------------------------------------
powerdns.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: powerdns-version: 0.4.1+version: 0.4.2 license: BSD-3-Clause license-file: LICENSE copyright: (c) 2021 Victor Nawothnig@@ -12,12 +12,12 @@ description: PowerDNS API allows programmatic manipulation of zones and other metadata. This library is a thin wrapper, exposing most of the idiosyncracies directly.- .+ Users are advised to refer to the PowerDNS documentation and its source code for the exact semantics.- .+ All exposed API endpoints are provided.- .+ > import qualified PowerDNS.Client as P > import Network.HTTP.Client (newManager, defaultManagerSettings) > import Servant.Client (runClientM, mkClientEnv, parseBarseUrl)@@ -58,7 +58,7 @@ ghc-options: -Wall -Wcompat build-depends: aeson ^>= { 1.5.6, 2.0.3.0 },- bytestring ^>= { 0.10.10 },+ bytestring ^>= { 0.10.10, 0.11.0 }, deepseq ^>= { 1.4.4 }, containers ^>= { 0.6.2 }, hashable ^>= { 1.3.0.0 },
spec/Spec.hs view
@@ -97,6 +97,12 @@ step "Add record to zone" runOk (updateZone "localhost" zoneId (patch added)) + step "Trigger notify"+ runOk (notifySlaves "localhost" zoneId)++ step "Trigger rectify"+ runOk (rectifyZone "localhost" zoneId)+ step "Delete a record" runOk (updateZone "localhost" zoneId (patch deleted))