packages feed

powerdns-0.2.0: PowerDNS/Client.hs

-- |
-- Module: PowerDNS.Client
-- Description: Servant client functions and utilities to interact with a PowerDNS Server
--
-- All the endpoints provide only a very slim wrapper around the PowerDNS API preserving
-- its idiosyncracies.

{-# LANGUAGE OverloadedStrings #-}
module PowerDNS.Client
  (
  -- * Authentication
    applyXApiKey

  -- * Version
  , listVersions
  , Version(..)

  -- * Zones
  --
  -- | See documentation at [PowerDNS Zones API](https://doc.powerdns.com/authoritative/http-api/zone.html)
  --
  -- Because the required fields of a 'Zone' differs between various requests and responses, every field
  -- is wrapped with Maybe. It is the users responsibility to check with the PowerDNS API to know when a
  -- field must be specified. For convenience 'empty' can be used to generate a value of 'Zone' with all
  -- fields set to 'Nothing'.
  --
  -- @
  --    let zone = empty { zone_name = Just "some.domain."
  --                     , zone_kind = Just Native
  --                     , zone_type = Just "zone" }
  --
  --    in createZone "localhost" -- Server ID
  --                  Nothing     -- Show RRsets in response
  --                  zone        -- The zone we are creating
  -- @
  , listZones
  , createZone
  , getZone
  , deleteZone
  , updateRecords
  , updateZone
  , triggerAxfr
  , notifySlaves
  , getZoneAxfr
  , rectifyZone
  -- ** Data types
  , Zone(..)
  , Kind(..)
  , RRSets(..)
  , RRSet(..)
  , Record(..)
  , Comment(..)
  , ChangeType(..)
  , RecordType(..)

  -- * Cryptokeys
  -- | See documentation at [PowerDNS Cryptokeys API](https://doc.powerdns.com/authoritative/http-api/cryptokey.html)
  , listCryptoKeys
  , createCryptokey
  , getCryptokey
  , updateCryptokey
  , deleteCryptokey
  -- ** Data types
  , Cryptokey

  -- * Servers
  -- | See documentation at [PowerDNS Servers API](https://doc.powerdns.com/authoritative/http-api/server.html)
  --
  -- Also contains [PowerDNS Search API](https://doc.powerdns.com/authoritative/http-api/search.html)
  -- and [PowerDNS Cache API](https://doc.powerdns.com/authoritative/http-api/cache.html)
  , listServers
  , getServer
  , search
  , flushCache
  , statistics
  -- ** Data types
  , Server(..)
  , SearchResult(..)
  , ObjectType(..)
  , CacheFlushResult(..)

  -- * Metadata
  -- | See documentation at [PowerDNS Metadata API](https://doc.powerdns.com/authoritative/http-api/metadata.html)
  , listMetadata
  , createMetadata
  , getMetadata
  , updateMetadata
  , deleteMetadata
  -- ** Data types
  , Metadata(..)

  -- * TSIGKeys
  -- | See documentation at [PowerDNS TSIGKeys API](https://doc.powerdns.com/authoritative/http-api/metadata.html)
  -- as well as related [TSIG documentation](https://doc.powerdns.com/authoritative/tsig.html)
  , listTSIGKeys
  , createTSIGKey
  , getTSIGKey
  , updateTSIGKey
  , deleteTSIGKey

  -- ** Data types
  , TSIGKey(..)
  , TSIGAlgorithm(..)

  -- * Utilities
  , empty
  )
where

import qualified Data.CaseInsensitive as CI
import           Data.Sequence ((|>))
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import           Servant.API (NoContent)
import           Servant.API.Generic (fromServant)
import           Servant.Client (ClientEnv(..), ClientM, client)
import           Servant.Client.Core.Request (Request, requestHeaders)
import           Servant.Client.Generic (AsClientT)

import           PowerDNS.API
import           PowerDNS.Internal.Utils (empty)

-- | Causes all requests with this 'ClientEnv' to be sent with the specified key embedded in a X-API-Key header.
applyXApiKey :: T.Text -- ^ API key
             -> ClientEnv
             -> ClientEnv
applyXApiKey key env = env { makeClientRequest = modified }
  where
    modified url = makeClientRequest env url . applyXApiKeyHeader key

applyXApiKeyHeader :: T.Text -> Request -> Request
applyXApiKeyHeader key req =
    req { requestHeaders = requestHeaders req |> authHeader }
  where
    authHeader = (CI.mk "X-API-Key", T.encodeUtf8 key)

----------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------

pdnsClient :: PowerDNS (AsClientT ClientM)
pdnsClient = fromServant (client api)

----------------------------------------------------------------------------------------

versionsClient :: VersionsAPI (AsClientT ClientM)
versionsClient = fromServant (versions pdnsClient)

-- | List the API versions and urls from the server. This is an undocumented endpoint.
listVersions :: ClientM [Version]
listVersions = apiListVersions versionsClient

----------------------------------------------------------------------------------------

zonesClient :: ZonesAPI (AsClientT ClientM)
zonesClient = fromServant (zones pdnsClient)

-- | List all zones for the server. See [Zones API Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#get--servers-server_id-zones)
listZones :: T.Text       -- ^ Server name
          -> Maybe T.Text -- ^ Limit to zone
          -> Maybe Bool   -- ^ Whether or not to include dnssec and edited_serial fields
          -> ClientM [Zone]
listZones = apiListZones zonesClient

-- | Create a new zone. See [Zones API Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#post--servers-server_id-zones)
--
-- 'empty' with record update syntax is useful avoid having to specify Nothing
-- for unwanted fields.
createZone :: T.Text       -- ^ Server name
           -> Maybe Bool   -- ^ Whether or not to include RRsets in the response
           -> Zone         -- ^ The zone to create
           -> ClientM Zone
createZone = apiCreateZone zonesClient

-- | Get details for zone. See [Zones API Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#get--servers-server_id-zones-zone_id)
getZone :: T.Text       -- ^ Server name
        -> T.Text       -- ^ Zone ID
        -> Maybe Bool   -- ^ Wheher or not to include RRsets in the response
        -> ClientM Zone
getZone = apiGetZone zonesClient

-- | Delete a given zone by id. See [Zones API Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#delete--servers-server_id-zones-zone_id)
deleteZone :: T.Text       -- ^ Server name
           -> T.Text       -- ^ Zone ID
           -> ClientM NoContent
deleteZone = apiDeleteZone zonesClient

-- | Update records of a zone. See [Zones API Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#patch--servers-server_id-zones-zone_id)
--
-- __Caution__: If rrset_records or rrset_comments is set to @Just []@ on a 'Delete' changetype,
-- this will delete all existing records or comments respectively for the domain.
updateRecords :: T.Text       -- ^ Server name
              -> T.Text       -- ^ Zone ID
              -> RRSets       -- ^ The RRsets to create, update or delete.
              -> ClientM NoContent
updateRecords = apiUpdateRecords zonesClient

-- | Modify zone. See [Zones API Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#put--servers-server_id-zones-zone_id)
--
-- 'empty' with record update syntax is useful avoid having to specify Nothing
-- for unwanted fields.
updateZone :: T.Text       -- ^ Server name
           -> T.Text       -- ^ Zone ID
           -> Zone         -- ^ Patch record. Fields with Just are changed, Nothing are ignored
           -> ClientM NoContent
updateZone = apiUpdateZone zonesClient

-- | 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
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
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
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
rectifyZone = apiRectifyZone zonesClient

----------------------------------------------------------------------------------------

cryptokeysClient :: CryptokeysAPI (AsClientT ClientM)
cryptokeysClient = fromServant (cryptokeys pdnsClient)

-- | List all crypto keys. See [Cryptokeys API Documentation](https://doc.powerdns.com/authoritative/http-api/cryptokey.html#get--servers-server_id-zones-zone_id-cryptokeys)
listCryptoKeys :: T.Text -- ^ Server name
               -> T.Text -- ^ Zone ID
               -> ClientM [Cryptokey]
listCryptoKeys = apiListCryptokeys cryptokeysClient

-- | Create a new crypto key. See [Cryptokeys API Documentation](https://doc.powerdns.com/authoritative/http-api/cryptokey.html#post--servers-server_id-zones-zone_id-cryptokeys)
createCryptokey :: T.Text            -- ^ Server name
                -> T.Text            -- ^ Zone ID
                -> Cryptokey         -- ^ Cryptokey to create
                -> ClientM Cryptokey -- ^ Created cryptokey
createCryptokey = apiCreateCryptokey cryptokeysClient

-- | Get existing crypto key. See [Cryptokeys API Documentation](https://doc.powerdns.com/authoritative/http-api/cryptokey.html#post--servers-server_id-zones-zone_id-cryptokeys)
getCryptokey :: T.Text -- ^ Server name
             -> T.Text -- ^ Zone ID
             -> T.Text -- ^ Cryptokey ID
             -> ClientM Cryptokey
getCryptokey = apiGetCryptokey cryptokeysClient

-- | Update existing crypto key. See [Cryptokeys API Documentation](https://doc.powerdns.com/authoritative/http-api/cryptokey.html#put--servers-server_id-zones-zone_id-cryptokeys-cryptokey_id)
updateCryptokey :: T.Text    -- ^ Server name
                -> T.Text    -- ^ Zone ID
                -> T.Text    -- ^ Cryptokey ID
                -> Cryptokey -- ^ Patch record. Fields with Just are changed, Nothing are ignored
                -> ClientM NoContent
updateCryptokey = apiUpdateCryptokey cryptokeysClient

-- | Delete existing crypto key. See [Cryptokeys API Documentation](https://doc.powerdns.com/authoritative/http-api/cryptokey.html#delete--servers-server_id-zones-zone_id-cryptokeys-cryptokey_id)
deleteCryptokey :: T.Text -- ^ Server name
                -> T.Text -- ^ Zone ID
                -> T.Text -- ^ Cryptokey ID
                -> ClientM NoContent
deleteCryptokey = apiDeleteCryptokey cryptokeysClient

----------------------------------------------------------------------------------------
serversClient :: ServersAPI (AsClientT ClientM)
serversClient = fromServant (servers pdnsClient)

-- | List available servers. See [Servers API Documentation](https://doc.powerdns.com/authoritative/http-api/server.html#get--servers)
listServers :: ClientM [Server]
listServers = apiListServers serversClient

-- | Get existing server. See [Servers API Documentation](https://doc.powerdns.com/authoritative/http-api/server.html#get--servers-server_id)
getServer :: T.Text -- ^ Server ID
          -> ClientM Server
getServer = apiGetServer serversClient

-- | Searches in various object types for an arbitrary string. See [Search API Documentation](https://doc.powerdns.com/authoritative/http-api/search.html#get--servers-server_id-search-data)
search :: T.Text           -- ^ Server ID
       -> T.Text           -- ^ String to search for
       -> Integer          -- ^ Maximum number of results
       -> Maybe ObjectType -- ^ Limit results to specified object type, if any.
       -> ClientM [SearchResult]
search = apiSearch serversClient

-- | Flushes a domain from the cache. See [Cache API Documentation](https://doc.powerdns.com/authoritative/http-api/cache.html#put--servers-server_id-cache-flush)
flushCache :: T.Text -- ^ Server ID
           -> T.Text -- ^ Domain
           -> ClientM CacheFlushResult
flushCache = apiFlushCache serversClient

-- | Get server wide statistics. See [Cache API Documentation](https://doc.powerdns.com/authoritative/http-api/statistics.html)
statistics :: T.Text       -- ^ Server ID
           -> Maybe T.Text -- ^ Only return statistic items with this name.
           -> Maybe Bool   -- ^ Whether or not to return ring items.
           -> ClientM [AnyStatisticItem]
statistics = apiStatistics serversClient

----------------------------------------------------------------------------------------
metadataClient :: MetadataAPI (AsClientT ClientM)
metadataClient = fromServant (metadata pdnsClient)

-- | List metadata for existing zone. See [Metadata API Documentation](https://doc.powerdns.com/authoritative/http-api/metadata.html#get--servers-server_id-zones-zone_id-metadata)
listMetadata :: T.Text -- ^ Server ID
             -> T.Text -- ^ Zone ID
             -> ClientM [Metadata]
listMetadata = apiListMetadata metadataClient

-- | Create metadata for zone. See [Metadata API Documentation](https://doc.powerdns.com/authoritative/http-api/metadata.html#post--servers-server_id-zones-zone_id-metadata)
createMetadata :: T.Text -- ^ Server ID
               -> T.Text -- ^ Zone ID
               -> Metadata
               -> ClientM NoContent
createMetadata = apiCreateMetadata metadataClient

-- | Get metadata for zone by kind. See [Metadata API Documentation](https://doc.powerdns.com/authoritative/http-api/metadata.html#get--servers-server_id-zones-zone_id-metadata-metadata_kind)
getMetadata :: T.Text -- ^ Server ID
            -> T.Text -- ^ Zone ID
            -> T.Text -- ^ Kind
            -> ClientM Metadata
getMetadata = apiGetMetadata metadataClient

-- | Update metadata for zone by kind. See [Metadata API Documentation](https://doc.powerdns.com/authoritative/http-api/metadata.html#put--servers-server_id-zones-zone_id-metadata-metadata_kind)
updateMetadata :: T.Text -- ^ Server ID
               -> T.Text -- ^ Zone ID
               -> T.Text -- ^ Kind
               -> Metadata
               -> ClientM Metadata
updateMetadata = apiUpdateMetadata metadataClient

-- | Delete metadata for zone by kind. See [Metadata API Documentation](https://doc.powerdns.com/authoritative/http-api/metadata.html#delete--servers-server_id-zones-zone_id-metadata-metadata_kind)
deleteMetadata :: T.Text -- ^ Server ID
               -> T.Text -- ^ Zone ID
               -> T.Text -- ^ Kind
               -> ClientM NoContent
deleteMetadata = apiDeleteMetadata metadataClient

----------------------------------------------------------------------------------------
tsigkeysClient :: TSIGKeysAPI (AsClientT ClientM)
tsigkeysClient = fromServant (tsigkeys pdnsClient)

-- | List all TSIG keys. See [TSIGKeys API Documentation](https://doc.powerdns.com/authoritative/http-api/tsigkey.html#get--servers-server_id-tsigkeys)
listTSIGKeys :: T.Text -> ClientM [TSIGKey]
listTSIGKeys = apiListTSIGKeys tsigkeysClient

-- | Create a new TSIG key. If the key is left empty, the server will generate one. See [TSIGKeys API Documentation](https://doc.powerdns.com/authoritative/http-api/tsigkey.html#post--servers-server_id-tsigkeys)
createTSIGKey :: T.Text -> TSIGKey -> ClientM TSIGKey
createTSIGKey = apiCreateTSIGKey tsigkeysClient

-- | Get TSIG key by its id. See [TSIGKeys API Documentation](https://doc.powerdns.com/authoritative/http-api/tsigkey.html#get--servers-server_id-tsigkeys-tsigkey_id)
getTSIGKey :: T.Text -> T.Text -> ClientM TSIGKey
getTSIGKey = apiGetTSIGKey tsigkeysClient

-- | Update existig TSIG key. See [TSIGKeys API Documentation](https://doc.powerdns.com/authoritative/http-api/tsigkey.html#put--servers-server_id-tsigkeys-tsigkey_id)
updateTSIGKey :: T.Text -> T.Text -> TSIGKey -> ClientM TSIGKey
updateTSIGKey = apiUpdateTSIGKey tsigkeysClient

-- | Delete existing TSIG key. See [TSIGKeys API Documentation](https://doc.powerdns.com/authoritative/http-api/tsigkey.html#delete--servers-server_id-tsigkeys-tsigkey_id)
deleteTSIGKey :: T.Text -> T.Text -> ClientM NoContent
deleteTSIGKey = apiDeleteTSIGKey tsigkeysClient

----------------------------------------------------------------------------------------