Propellor can configure primary DNS servers, including generating zone files, which is done by looking at the properties of hosts in a domain.
This commit is contained in:
parent
7e9853520b
commit
d1db64b3bc
|
@ -49,6 +49,12 @@ aka domain = pureAttrProperty ("aka " ++ domain)
|
||||||
addDNS :: Record -> SetAttr
|
addDNS :: Record -> SetAttr
|
||||||
addDNS record d = d { _dns = S.insert record (_dns d) }
|
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 :: String -> Property
|
||||||
sshPubKey k = pureAttrProperty ("ssh pubkey known") $
|
sshPubKey k = pureAttrProperty ("ssh pubkey known") $
|
||||||
\d -> d { _sshPubKey = Just k }
|
\d -> d { _sshPubKey = Just k }
|
||||||
|
|
|
@ -2,7 +2,6 @@ module Propellor.Property.Dns (
|
||||||
module Propellor.Types.Dns,
|
module Propellor.Types.Dns,
|
||||||
primary,
|
primary,
|
||||||
secondary,
|
secondary,
|
||||||
servingZones,
|
|
||||||
mkSOA,
|
mkSOA,
|
||||||
rootAddressesFrom,
|
rootAddressesFrom,
|
||||||
writeZoneFile,
|
writeZoneFile,
|
||||||
|
@ -26,8 +25,6 @@ import Data.List
|
||||||
|
|
||||||
-- | Primary dns server for a domain.
|
-- | 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
|
-- Most of the content of the zone file is configured by setting properties
|
||||||
-- of hosts. For example,
|
-- of hosts. For example,
|
||||||
--
|
--
|
||||||
|
@ -35,41 +32,71 @@ import Data.List
|
||||||
-- > & ipv4 "192.168.1.1"
|
-- > & ipv4 "192.168.1.1"
|
||||||
-- > & aka "mail.exmaple.com"
|
-- > & 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
|
-- The [(Domain, Record)] list can be used for additional records
|
||||||
-- that cannot be configured elsewhere. For example, it might contain
|
-- that cannot be configured elsewhere. For example, it might contain
|
||||||
-- CNAMEs pointing at hosts that propellor does not control.
|
-- CNAMEs pointing at hosts that propellor does not control.
|
||||||
primary :: [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> Property
|
primary :: [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> Property
|
||||||
primary hosts domain soa rs = withwarnings (check needupdate baseprop)
|
primary hosts domain soa rs = withwarnings (check needupdate baseprop)
|
||||||
`requires` Apt.serviceInstalledRunning "bind9"
|
`requires` servingZones
|
||||||
`onChange` Service.reloaded "bind9"
|
`onChange` Service.reloaded "bind9"
|
||||||
where
|
where
|
||||||
(partialzone, warnings) = genZone hosts domain soa
|
(partialzone, warnings) = genZone hosts domain soa
|
||||||
zone = partialzone { zHosts = zHosts partialzone ++ rs }
|
zone = partialzone { zHosts = zHosts partialzone ++ rs }
|
||||||
zonefile = "/etc/bind/propellor/db." ++ domain
|
zonefile = "/etc/bind/propellor/db." ++ domain
|
||||||
needupdate = (/= Just zone) <$> readZonePropellorFile zonefile
|
baseprop = Property ("dns primary for " ++ domain)
|
||||||
baseprop = property ("dns primary for " ++ domain) $ makeChange $ do
|
(makeChange $ writeZoneFile zone zonefile)
|
||||||
writeZoneFile zone zonefile
|
(addNamedConf conf)
|
||||||
withwarnings p = adjustProperty p $ \satisfy -> do
|
withwarnings p = adjustProperty p $ \satisfy -> do
|
||||||
mapM_ warningMessage warnings
|
mapM_ warningMessage warnings
|
||||||
satisfy
|
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
|
-- | Secondary dns server for a domain.
|
||||||
namedconf = "/etc/bind/named.conf.local"
|
secondary :: [Host] -> Domain -> HostName -> Property
|
||||||
|
secondary hosts domain master = pureAttrProperty desc (addNamedConf conf)
|
||||||
zoneDesc :: NamedConf -> String
|
`requires` servingZones
|
||||||
zoneDesc z = confDomain z ++ " (" ++ show (confType z) ++ ")"
|
where
|
||||||
|
desc = "dns secondary for " ++ domain
|
||||||
secondary :: Domain -> [IPAddr] -> NamedConf
|
conf = NamedConf
|
||||||
secondary domain masters = NamedConf
|
|
||||||
{ confDomain = domain
|
{ confDomain = domain
|
||||||
, confType = Secondary
|
, confType = Secondary
|
||||||
, confFile = "db." ++ domain
|
, confFile = "db." ++ domain
|
||||||
, confMasters = masters
|
, confMasters = hostAddresses master hosts
|
||||||
, confLines = ["allow-transfer { }"]
|
, 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 :: NamedConf -> [Line]
|
||||||
confStanza c =
|
confStanza c =
|
||||||
[ "// automatically generated by propellor"
|
[ "// automatically generated by propellor"
|
||||||
|
@ -89,13 +116,8 @@ confStanza c =
|
||||||
(map (\ip -> "\t\t" ++ fromIPAddr ip ++ ";") (confMasters c)) ++
|
(map (\ip -> "\t\t" ++ fromIPAddr ip ++ ";") (confMasters c)) ++
|
||||||
[ "\t};" ]
|
[ "\t};" ]
|
||||||
|
|
||||||
-- | Rewrites the whole named.conf.local file to serve the specified
|
namedConfFile :: FilePath
|
||||||
-- zones.
|
namedConfFile = "/etc/bind/named.conf.local"
|
||||||
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"
|
|
||||||
|
|
||||||
-- | Generates a SOA with some fairly sane numbers in it.
|
-- | Generates a SOA with some fairly sane numbers in it.
|
||||||
--
|
--
|
||||||
|
|
|
@ -9,8 +9,9 @@ import qualified Data.Set as S
|
||||||
data Attr = Attr
|
data Attr = Attr
|
||||||
{ _hostname :: HostName
|
{ _hostname :: HostName
|
||||||
, _os :: Maybe System
|
, _os :: Maybe System
|
||||||
, _dns :: S.Set Dns.Record
|
|
||||||
, _sshPubKey :: Maybe String
|
, _sshPubKey :: Maybe String
|
||||||
|
, _dns :: S.Set Dns.Record
|
||||||
|
, _namedconf :: S.Set Dns.NamedConf
|
||||||
|
|
||||||
, _dockerImage :: Maybe String
|
, _dockerImage :: Maybe String
|
||||||
, _dockerRunParams :: [HostName -> String]
|
, _dockerRunParams :: [HostName -> String]
|
||||||
|
@ -21,6 +22,7 @@ instance Eq Attr where
|
||||||
[ _hostname x == _hostname y
|
[ _hostname x == _hostname y
|
||||||
, _os x == _os y
|
, _os x == _os y
|
||||||
, _dns x == _dns y
|
, _dns x == _dns y
|
||||||
|
, _namedconf x == _namedconf y
|
||||||
, _sshPubKey x == _sshPubKey y
|
, _sshPubKey x == _sshPubKey y
|
||||||
|
|
||||||
, _dockerImage x == _dockerImage y
|
, _dockerImage x == _dockerImage y
|
||||||
|
@ -32,13 +34,14 @@ instance Show Attr where
|
||||||
show a = unlines
|
show a = unlines
|
||||||
[ "hostname " ++ _hostname a
|
[ "hostname " ++ _hostname a
|
||||||
, "OS " ++ show (_os a)
|
, "OS " ++ show (_os a)
|
||||||
, "dns " ++ show (_dns a)
|
|
||||||
, "sshPubKey " ++ show (_sshPubKey a)
|
, "sshPubKey " ++ show (_sshPubKey a)
|
||||||
|
, "dns " ++ show (_dns a)
|
||||||
|
, "namedconf " ++ show (_namedconf a)
|
||||||
, "docker image " ++ show (_dockerImage a)
|
, "docker image " ++ show (_dockerImage a)
|
||||||
, "docker run params " ++ show (map (\mk -> mk "") (_dockerRunParams a))
|
, "docker run params " ++ show (map (\mk -> mk "") (_dockerRunParams a))
|
||||||
]
|
]
|
||||||
|
|
||||||
newAttr :: HostName -> Attr
|
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
|
type SetAttr = Attr -> Attr
|
||||||
|
|
|
@ -19,10 +19,10 @@ data NamedConf = NamedConf
|
||||||
, confMasters :: [IPAddr]
|
, confMasters :: [IPAddr]
|
||||||
, confLines :: [String]
|
, confLines :: [String]
|
||||||
}
|
}
|
||||||
deriving (Show, Eq)
|
deriving (Show, Eq, Ord)
|
||||||
|
|
||||||
data Type = Master | Secondary
|
data Type = Master | Secondary
|
||||||
deriving (Show, Eq)
|
deriving (Show, Eq, Ord)
|
||||||
|
|
||||||
-- | Represents a bind 9 zone file.
|
-- | Represents a bind 9 zone file.
|
||||||
data Zone = Zone
|
data Zone = Zone
|
||||||
|
|
|
@ -65,17 +65,6 @@ hosts = -- (o) `
|
||||||
& Docker.garbageCollected `period` Daily
|
& Docker.garbageCollected `period` Daily
|
||||||
& Apt.installed ["git-annex", "mtr", "screen"]
|
& 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.
|
-- Orca is the main git-annex build box.
|
||||||
, standardSystem "orca.kitenet.net" Unstable "amd64"
|
, standardSystem "orca.kitenet.net" Unstable "amd64"
|
||||||
& ipv4 "138.38.108.179"
|
& ipv4 "138.38.108.179"
|
||||||
|
@ -101,7 +90,7 @@ hosts = -- (o) `
|
||||||
& Ssh.hostKey SshEcdsa
|
& Ssh.hostKey SshEcdsa
|
||||||
& Apt.unattendedUpgrades
|
& Apt.unattendedUpgrades
|
||||||
& Apt.serviceInstalledRunning "ntp"
|
& Apt.serviceInstalledRunning "ntp"
|
||||||
& Dns.servingZones myDnsSecondary
|
& myDnsSecondary
|
||||||
& Postfix.satellite
|
& Postfix.satellite
|
||||||
|
|
||||||
& Apt.serviceInstalledRunning "apache2"
|
& Apt.serviceInstalledRunning "apache2"
|
||||||
|
@ -133,6 +122,17 @@ hosts = -- (o) `
|
||||||
& aka "nntp.olduse.net"
|
& aka "nntp.olduse.net"
|
||||||
& JoeySites.oldUseNetServer hosts
|
& 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"]
|
& Apt.installed ["ntop"]
|
||||||
|
|
||||||
|
|
||||||
|
@ -244,17 +244,17 @@ cleanCloudAtCost = propertyList "cloudatcost cleanup"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
myDnsSecondary :: [Dns.NamedConf]
|
myDnsSecondary :: Property
|
||||||
myDnsSecondary =
|
myDnsSecondary = propertyList "dns secondary for all my domains"
|
||||||
[ Dns.secondary "kitenet.net" master
|
[ Dns.secondary hosts "kitenet.net" master
|
||||||
, Dns.secondary "joeyh.name" master
|
, Dns.secondary hosts "joeyh.name" master
|
||||||
, Dns.secondary "ikiwiki.info" master
|
, Dns.secondary hosts "ikiwiki.info" master
|
||||||
, Dns.secondary "olduse.net" master
|
, Dns.secondary hosts "olduse.net" master
|
||||||
, Dns.secondary "branchable.com" branchablemaster
|
, Dns.secondary hosts "branchable.com" branchablemaster
|
||||||
]
|
]
|
||||||
where
|
where
|
||||||
master = hostAddresses "wren.kitenet.net" hosts
|
master = "wren.kitenet.net"
|
||||||
branchablemaster = hostAddresses "branchable.com" hosts
|
branchablemaster = "branchable.com"
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = defaultMain hosts
|
main = defaultMain hosts
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
propellor (0.4.0) UNRELEASED; urgency=medium
|
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.
|
* All Property combinators now combine together their Attr settings.
|
||||||
So Attr settings can be made inside a propertyList, for example.
|
So Attr settings can be made inside a propertyList, for example.
|
||||||
* Run all cron jobs under chronic from moreutils to avoid unnecessary
|
* Run all cron jobs under chronic from moreutils to avoid unnecessary
|
||||||
mails.
|
mails.
|
||||||
* The `cname` property was renamed to `aka` as it does not always generate
|
|
||||||
CNAME in the DNS.
|
|
||||||
|
|
||||||
-- Joey Hess <joeyh@debian.org> Thu, 17 Apr 2014 21:00:43 -0400
|
-- Joey Hess <joeyh@debian.org> Thu, 17 Apr 2014 21:00:43 -0400
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue