Skip to content

Commit

Permalink
Merge pull request #54 from vst/46-list-domains-managed-on-hetzner
Browse files Browse the repository at this point in the history
feat: list domains managed on Hetzner
  • Loading branch information
vst authored May 15, 2024
2 parents b1d9632 + 202f034 commit 9431310
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 10 deletions.
4 changes: 4 additions & 0 deletions config_sample.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ cloud_profiles:
- type: "hetzner"
value:
token: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
- type: "hetzner"
value:
token: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
token_dns: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
11 changes: 11 additions & 0 deletions config_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@
"token": {
"$comment": "Hetzner API token.",
"type": "string"
},
"token_dns": {
"$comment": "Hetzner DNS API token.",
"anyOf": [
{
"type": "null"
},
{
"type": "string"
}
]
}
},
"required": ["token"],
Expand Down
8 changes: 6 additions & 2 deletions src/Clompse/Programs/ListDomains.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import qualified Autodocodec as ADC
import Clompse.Config (CloudConnection (..), CloudProfile (..), Config (..))
import qualified Clompse.Providers.Aws as Providers.Aws
import qualified Clompse.Providers.Do as Providers.Do
import qualified Clompse.Providers.Hetzner as Providers.Hetzner
import qualified Clompse.Types as Types
import qualified Control.Concurrent.Async.Pool as Async
import Control.Monad.Except (runExceptT)
Expand Down Expand Up @@ -78,8 +79,11 @@ listDomainsForCloudConnection (CloudConnectionDo conn) = do
case eRecords of
Left e -> _log (" ERROR (DO Domains): " <> Z.Text.tshow e) >> pure []
Right records -> pure records
listDomainsForCloudConnection (CloudConnectionHetzner _conn) = do
pure []
listDomainsForCloudConnection (CloudConnectionHetzner conn) = do
eRecords <- runExceptT (Providers.Hetzner.listDomains conn)
case eRecords of
Left e -> _log (" ERROR (Hetzner Domains): " <> Z.Text.tshow e) >> pure []
Right records -> pure records


_log :: MonadIO m => T.Text -> m ()
Expand Down
3 changes: 2 additions & 1 deletion src/Clompse/Providers/Hetzner.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
module Clompse.Providers.Hetzner (
HetznerError (..),
HetznerConnection (..),
listDomains,
listServers,
) where

import Clompse.Providers.Hetzner.Api (listServers)
import Clompse.Providers.Hetzner.Api (listDomains, listServers)
import Clompse.Providers.Hetzner.Connection (HetznerConnection (..))
import Clompse.Providers.Hetzner.Error (HetznerError (..))

21 changes: 20 additions & 1 deletion src/Clompse/Providers/Hetzner/Api.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
-- convert responses to Clompse types.
module Clompse.Providers.Hetzner.Api where

import Clompse.Providers.Hetzner.Connection (HetznerConnection (..), hetznerConnectionToken)
import Clompse.Providers.Hetzner.Connection (HetznerConnection (..), hetznerConnectionToken, hetznerConnectionTokenDns)
import Clompse.Providers.Hetzner.Error (HetznerError)
import qualified Clompse.Types as Types
import Control.Monad.Except (MonadError)
Expand All @@ -18,6 +18,7 @@ import Data.Maybe (mapMaybe, maybeToList)
import qualified Data.Text as T
import qualified Data.Time as Time
import qualified Hetzner.Cloud as Hetzner
import qualified Hetzner.DNS as Hetzner
import qualified Net.IPv4
import qualified Net.IPv6
import qualified Zamazingo.Net as Z.Net
Expand All @@ -38,6 +39,24 @@ listServers = do
fmap (fmap toServer) . apiListServersFirewalls


-- | Lists all domains managed in the Hetzner account associated with
-- the given connection.
listDomains
:: MonadIO m
=> MonadError HetznerError m
=> HetznerConnection
-> m [Types.Domain]
listDomains conn = do
zones <- maybe (pure []) (Hetzner.streamToList . Hetzner.streamPages . Hetzner.getZones) (hetznerConnectionTokenDns conn)
pure $ fmap toDomain zones
where
toDomain Hetzner.Zone {..} =
Types.Domain
{ _domainName = zoneName
, _domainProvider = Types.ProviderHetzner
}


-- * Helpers


Expand Down
27 changes: 21 additions & 6 deletions src/Clompse/Providers/Hetzner/Connection.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,18 @@ import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import GHC.Generics (Generic)
import qualified Hetzner.Cloud as Hetzner
import qualified Hetzner.DNS as Hetzner.Dns


-- | Data definition for Hetzner API connection configuration.
--
-- >>> Aeson.encode $ HetznerConnection "my-token"
-- "{\"token\":\"my-token\"}"
-- >>> Aeson.encode $ HetznerConnection "my-token" Nothing
-- "{\"token\":\"my-token\",\"token_dns\":null}"
-- >>> Aeson.decode "{\"token\":\"my-token\"}" :: Maybe HetznerConnection
-- Just (HetznerConnection {_hetznerConnectionToken = "my-token"})
newtype HetznerConnection = HetznerConnection
{ _hetznerConnectionToken :: T.Text
-- Just (HetznerConnection {_hetznerConnectionToken = "my-token", _hetznerConnectionTokenDns = Nothing})
data HetznerConnection = HetznerConnection
{ _hetznerConnectionToken :: !T.Text
, _hetznerConnectionTokenDns :: !(Maybe T.Text)
}
deriving (Eq, Generic, Show)
deriving (Aeson.FromJSON, Aeson.ToJSON) via (ADC.Autodocodec HetznerConnection)
Expand All @@ -35,13 +37,26 @@ instance ADC.HasCodec HetznerConnection where
ADC.object "HetznerConnection" $
HetznerConnection
<$> ADC.requiredField "token" "Hetzner API token." ADC..= _hetznerConnectionToken
<*> ADC.optionalFieldWithDefault "token_dns" Nothing "Hetzner DNS API token." ADC..= _hetznerConnectionTokenDns


-- | Extracts the Hetzner API token from a connection configuration
-- and builds a 'Hetzner.Token' value.
--
-- >>> hetznerConnectionToken (HetznerConnection "my-token")
-- >>> hetznerConnectionToken (HetznerConnection "my-token" Nothing)
-- Token "my-token"
hetznerConnectionToken :: HetznerConnection -> Hetzner.Token
hetznerConnectionToken =
Hetzner.Token . TE.encodeUtf8 . _hetznerConnectionToken


-- | Extracts the Hetzner API token from a connection configuration
-- and builds a 'Hetzner.Token' value (for DNS API).
--
-- >>> hetznerConnectionTokenDns (HetznerConnection "my-token" Nothing)
-- Nothing
-- >>> hetznerConnectionTokenDns (HetznerConnection "my-token" (Just "my-dns-token"))
-- Just (Token "my-dns-token")
hetznerConnectionTokenDns :: HetznerConnection -> Maybe Hetzner.Dns.Token
hetznerConnectionTokenDns =
fmap (Hetzner.Dns.Token . TE.encodeUtf8) . _hetznerConnectionTokenDns

0 comments on commit 9431310

Please sign in to comment.