diff --git a/Propellor/Attr.hs b/Propellor/Attr.hs index 8c4a2ad..a54d883 100644 --- a/Propellor/Attr.hs +++ b/Propellor/Attr.hs @@ -49,6 +49,12 @@ aka domain = pureAttrProperty ("aka " ++ domain) addDNS :: Record -> SetAttr addDNS record d = d { _dns = S.insert record (_dns d) } +addNamedConf :: NamedConf -> SetAttr +addNamedConf conf d = d { _namedconf = S.insert conf (_namedconf d) } + +getNamedConf :: Propellor (S.Set NamedConf) +getNamedConf = asks _namedconf + sshPubKey :: String -> Property sshPubKey k = pureAttrProperty ("ssh pubkey known") $ \d -> d { _sshPubKey = Just k } diff --git a/Propellor/Property/Dns.hs b/Propellor/Property/Dns.hs index 7c26f1d..90556d2 100644 --- a/Propellor/Property/Dns.hs +++ b/Propellor/Property/Dns.hs @@ -2,7 +2,6 @@ module Propellor.Property.Dns ( module Propellor.Types.Dns, primary, secondary, - servingZones, mkSOA, rootAddressesFrom, writeZoneFile, @@ -26,8 +25,6 @@ import Data.List -- | Primary dns server for a domain. -- --- TODO: Does not yet add it to named.conf.local. --- -- Most of the content of the zone file is configured by setting properties -- of hosts. For example, -- @@ -35,40 +32,70 @@ import Data.List -- > & ipv4 "192.168.1.1" -- > & aka "mail.exmaple.com" -- --- Will cause that host and its cnames to appear in the zone file. +-- Will cause that hostmame and its alias to appear in the zone file, +-- with the configured IP address. -- -- The [(Domain, Record)] list can be used for additional records -- that cannot be configured elsewhere. For example, it might contain -- CNAMEs pointing at hosts that propellor does not control. primary :: [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> Property primary hosts domain soa rs = withwarnings (check needupdate baseprop) - `requires` Apt.serviceInstalledRunning "bind9" + `requires` servingZones `onChange` Service.reloaded "bind9" where (partialzone, warnings) = genZone hosts domain soa zone = partialzone { zHosts = zHosts partialzone ++ rs } zonefile = "/etc/bind/propellor/db." ++ domain - needupdate = (/= Just zone) <$> readZonePropellorFile zonefile - baseprop = property ("dns primary for " ++ domain) $ makeChange $ do - writeZoneFile zone zonefile + baseprop = Property ("dns primary for " ++ domain) + (makeChange $ writeZoneFile zone zonefile) + (addNamedConf conf) withwarnings p = adjustProperty p $ \satisfy -> do mapM_ warningMessage warnings satisfy + conf = NamedConf + { confDomain = domain + , confType = Master + , confFile = zonefile + , confMasters = [] + , confLines = [] + } + needupdate = do + v <- readZonePropellorFile zonefile + return $ case v of + Nothing -> True + Just oldzone -> + -- compare everything except serial + let oldserial = sSerialĀ (zSOA oldzone) + z = zone { zSOA = (zSOA zone) { sSerial = oldserial } } + in z /= oldzone || oldserial < sSerial (zSOA zone) -namedconf :: FilePath -namedconf = "/etc/bind/named.conf.local" +-- | Secondary dns server for a domain. +secondary :: [Host] -> Domain -> HostName -> Property +secondary hosts domain master = pureAttrProperty desc (addNamedConf conf) + `requires` servingZones + where + desc = "dns secondary for " ++ domain + conf = NamedConf + { confDomain = domain + , confType = Secondary + , confFile = "db." ++ domain + , confMasters = hostAddresses master hosts + , confLines = ["allow-transfer { }"] + } -zoneDesc :: NamedConf -> String -zoneDesc z = confDomain z ++ " (" ++ show (confType z) ++ ")" - -secondary :: Domain -> [IPAddr] -> NamedConf -secondary domain masters = NamedConf - { confDomain = domain - , confType = Secondary - , confFile = "db." ++ domain - , confMasters = masters - , confLines = ["allow-transfer { }"] - } +-- | Rewrites the whole named.conf.local file to serve the zones +-- configured by `primary` and `secondary`, and ensures that bind9 is +-- running. +servingZones :: Property +servingZones = property "serving configured dns zones" go + `requires` Apt.serviceInstalledRunning "bind9" + `onChange` Service.reloaded "bind9" + where + go = do + zs <- getNamedConf + ensureProperty $ + hasContent namedConfFile $ + concatMap confStanza $ S.toList zs confStanza :: NamedConf -> [Line] confStanza c = @@ -89,13 +116,8 @@ confStanza c = (map (\ip -> "\t\t" ++ fromIPAddr ip ++ ";") (confMasters c)) ++ [ "\t};" ] --- | Rewrites the whole named.conf.local file to serve the specified --- zones. -servingZones :: [NamedConf] -> Property -servingZones zs = hasContent namedconf (concatMap confStanza zs) - `describe` ("dns server for zones: " ++ unwords (map zoneDesc zs)) - `requires` Apt.serviceInstalledRunning "bind9" - `onChange` Service.reloaded "bind9" +namedConfFile :: FilePath +namedConfFile = "/etc/bind/named.conf.local" -- | Generates a SOA with some fairly sane numbers in it. -- diff --git a/Propellor/Types/Attr.hs b/Propellor/Types/Attr.hs index cf8bdf1..f64b048 100644 --- a/Propellor/Types/Attr.hs +++ b/Propellor/Types/Attr.hs @@ -9,8 +9,9 @@ import qualified Data.Set as S data Attr = Attr { _hostname :: HostName , _os :: Maybe System - , _dns :: S.Set Dns.Record , _sshPubKey :: Maybe String + , _dns :: S.Set Dns.Record + , _namedconf :: S.Set Dns.NamedConf , _dockerImage :: Maybe String , _dockerRunParams :: [HostName -> String] @@ -21,6 +22,7 @@ instance Eq Attr where [ _hostname x == _hostname y , _os x == _os y , _dns x == _dns y + , _namedconf x == _namedconf y , _sshPubKey x == _sshPubKey y , _dockerImage x == _dockerImage y @@ -32,13 +34,14 @@ instance Show Attr where show a = unlines [ "hostname " ++ _hostname a , "OS " ++ show (_os a) - , "dns " ++ show (_dns a) , "sshPubKey " ++ show (_sshPubKey a) + , "dns " ++ show (_dns a) + , "namedconf " ++ show (_namedconf a) , "docker image " ++ show (_dockerImage a) , "docker run params " ++ show (map (\mk -> mk "") (_dockerRunParams a)) ] newAttr :: HostName -> Attr -newAttr hn = Attr hn Nothing S.empty Nothing Nothing [] +newAttr hn = Attr hn Nothing Nothing S.empty S.empty Nothing [] type SetAttr = Attr -> Attr diff --git a/Propellor/Types/Dns.hs b/Propellor/Types/Dns.hs index 9d801ef..e367202 100644 --- a/Propellor/Types/Dns.hs +++ b/Propellor/Types/Dns.hs @@ -19,10 +19,10 @@ data NamedConf = NamedConf , confMasters :: [IPAddr] , confLines :: [String] } - deriving (Show, Eq) + deriving (Show, Eq, Ord) data Type = Master | Secondary - deriving (Show, Eq) + deriving (Show, Eq, Ord) -- | Represents a bind 9 zone file. data Zone = Zone diff --git a/config-joey.hs b/config-joey.hs index eae3a15..e49a062 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -64,17 +64,6 @@ hosts = -- (o) ` & Docker.garbageCollected `period` Daily & Apt.installed ["git-annex", "mtr", "screen"] - - & Dns.primary hosts "olduse.net" - ( Dns.mkSOA "ns1.kitenet.net" 100 - [ NS (AbsDomain "ns1.kitenet.net") - , NS (AbsDomain "ns6.gandi.net") - , NS (AbsDomain "ns2.kitenet.net") - , MX 0 (AbsDomain "kitenet.net") - , TXT "v=spf1 a -all" - ] - ) - [ (RelDomain "article", CNAME $ AbsDomain "virgil.koldfront.dk") ] -- Orca is the main git-annex build box. , standardSystem "orca.kitenet.net" Unstable "amd64" @@ -101,7 +90,7 @@ hosts = -- (o) ` & Ssh.hostKey SshEcdsa & Apt.unattendedUpgrades & Apt.serviceInstalledRunning "ntp" - & Dns.servingZones myDnsSecondary + & myDnsSecondary & Postfix.satellite & Apt.serviceInstalledRunning "apache2" @@ -133,6 +122,17 @@ hosts = -- (o) ` & aka "nntp.olduse.net" & JoeySites.oldUseNetServer hosts + & Dns.primary hosts "olduse.net" + ( Dns.mkSOA "ns1.kitenet.net" 100 + [ NS (AbsDomain "ns1.kitenet.net") + , NS (AbsDomain "ns6.gandi.net") + , NS (AbsDomain "ns2.kitenet.net") + , MX 0 (AbsDomain "kitenet.net") + , TXT "v=spf1 a -all" + ] + ) + [ (RelDomain "article", CNAME $ AbsDomain "virgil.koldfront.dk") ] + & Apt.installed ["ntop"] @@ -244,17 +244,17 @@ cleanCloudAtCost = propertyList "cloudatcost cleanup" ] ] -myDnsSecondary :: [Dns.NamedConf] -myDnsSecondary = - [ Dns.secondary "kitenet.net" master - , Dns.secondary "joeyh.name" master - , Dns.secondary "ikiwiki.info" master - , Dns.secondary "olduse.net" master - , Dns.secondary "branchable.com" branchablemaster +myDnsSecondary :: Property +myDnsSecondary = propertyList "dns secondary for all my domains" + [ Dns.secondary hosts "kitenet.net" master + , Dns.secondary hosts "joeyh.name" master + , Dns.secondary hosts "ikiwiki.info" master + , Dns.secondary hosts "olduse.net" master + , Dns.secondary hosts "branchable.com" branchablemaster ] where - master = hostAddresses "wren.kitenet.net" hosts - branchablemaster = hostAddresses "branchable.com" hosts + master = "wren.kitenet.net" + branchablemaster = "branchable.com" main :: IO () main = defaultMain hosts diff --git a/debian/changelog b/debian/changelog index 2442dd1..463b181 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,12 +1,15 @@ propellor (0.4.0) UNRELEASED; urgency=medium - * Constructor of Property has changed (use property function instead). + * Propellor can configure primary DNS servers, including generating + zone files, which is done by looking at the properties of hosts + in a domain. + * The `cname` property was renamed to `aka` as it does not always generate + CNAME in the DNS. + * Constructor of Property has changed (use `property` function instead). * All Property combinators now combine together their Attr settings. So Attr settings can be made inside a propertyList, for example. * Run all cron jobs under chronic from moreutils to avoid unnecessary mails. - * The `cname` property was renamed to `aka` as it does not always generate - CNAME in the DNS. -- Joey Hess Thu, 17 Apr 2014 21:00:43 -0400