diff options
| author | Joey Hess <joey@kitenet.net> | 2014-04-24 18:10:23 -0400 |
|---|---|---|
| committer | Joey Hess <joey@kitenet.net> | 2014-04-24 18:10:23 -0400 |
| commit | c4f364b249b810410d329a932dea883f36b9a712 (patch) | |
| tree | d4d4ee86efba15249284a41841e17654d901f1f3 /Propellor | |
| parent | 792957153ca9c22de28da7be83940aa5e07af0fa (diff) | |
| parent | 72a6b1c759906025fd6761aeb5ef51e64e60abd7 (diff) | |
Merge branch 'joeyconfig'
Diffstat (limited to 'Propellor')
| -rw-r--r-- | Propellor/Attr.hs | 2 | ||||
| -rw-r--r-- | Propellor/CmdLine.hs | 28 | ||||
| -rw-r--r-- | Propellor/Property/Dns.hs | 63 | ||||
| -rw-r--r-- | Propellor/Types/Dns.hs | 16 |
4 files changed, 88 insertions, 21 deletions
diff --git a/Propellor/Attr.hs b/Propellor/Attr.hs index acaf28db..98cfc64d 100644 --- a/Propellor/Attr.hs +++ b/Propellor/Attr.hs @@ -59,7 +59,7 @@ addNamedConf conf d = d { _namedconf = new } where m = _namedconf d domain = confDomain conf - new = case (confType conf, confType <$> M.lookup domain m) of + new = case (confDnsServerType conf, confDnsServerType <$> M.lookup domain m) of (Secondary, Just Master) -> m _ -> M.insert domain conf m diff --git a/Propellor/CmdLine.hs b/Propellor/CmdLine.hs index 5be91c4f..ad04abe6 100644 --- a/Propellor/CmdLine.hs +++ b/Propellor/CmdLine.hs @@ -10,6 +10,7 @@ import System.Log.Handler.Simple import System.PosixCompat import Control.Exception (bracket) import System.Posix.IO +import Data.Time.Clock.POSIX import Propellor import qualified Propellor.Property.Docker as Docker @@ -346,14 +347,37 @@ checkDebugMode = go =<< getEnv "PROPELLOR_DEBUG" setLevel DEBUG . setHandlers [f] go _ = noop --- Parameters can be passed to both ssh and scp. +-- Parameters can be passed to both ssh and scp, to enable a ssh connection +-- caching socket. +-- +-- If the socket already exists, check if its mtime is older than 10 +-- minutes, and if so stop that ssh process, in order to not try to +-- use an old stale connection. (atime would be nicer, but there's +-- a good chance a laptop uses noatime) sshCachingParams :: HostName -> IO [CommandParam] sshCachingParams hn = do home <- myHomeDir let cachedir = home </> ".ssh" </> "propellor" createDirectoryIfMissing False cachedir let socketfile = cachedir </> hn ++ ".sock" - return + let ps = [ Param "-o", Param ("ControlPath=" ++ socketfile) , Params "-o ControlMaster=auto -o ControlPersist=yes" ] + + maybe noop (expireold ps socketfile) + =<< catchMaybeIO (getFileStatus socketfile) + + return ps + + where + expireold ps f s = do + now <- truncate <$> getPOSIXTime :: IO Integer + if modificationTime s > fromIntegral now - tenminutes + then touchFile f + else do + void $ boolSystem "ssh" $ + [ Params "-O stop" ] ++ ps ++ + [ Param "localhost" ] + nukeFile f + tenminutes = 600 diff --git a/Propellor/Property/Dns.hs b/Propellor/Property/Dns.hs index 40cadb6d..5c3162cb 100644 --- a/Propellor/Property/Dns.hs +++ b/Propellor/Property/Dns.hs @@ -40,6 +40,17 @@ import Data.List -- that cannot be configured elsewhere. This often includes NS records, -- TXT records and perhaps CNAMEs pointing at hosts that propellor does -- not control. +-- +-- The primary server is configured to only allow zone transfers to +-- secondary dns servers. These are determined in two ways: +-- +-- 1. By looking at the properties of other hosts, to find hosts that +-- are configured as the secondary dns server. +-- +-- 2. By looking for NS Records in the passed list of records. +-- +-- In either case, the secondary dns server Host should have an ipv4 and/or +-- ipv6 property defined. primary :: [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> RevertableProperty primary hosts domain soa rs = RevertableProperty setup cleanup where @@ -52,22 +63,31 @@ primary hosts domain soa rs = RevertableProperty setup cleanup `requires` namedConfWritten `onChange` Service.reloaded "bind9" - (partialzone, warnings) = genZone hosts domain soa + (partialzone, zonewarnings) = genZone hosts domain soa zone = partialzone { zHosts = zHosts partialzone ++ rs } zonefile = "/etc/bind/propellor/db." ++ domain baseprop = Property ("dns primary for " ++ domain) (makeChange $ writeZoneFile zone zonefile) (addNamedConf conf) withwarnings p = adjustProperty p $ \satisfy -> do - mapM_ warningMessage warnings + mapM_ warningMessage $ zonewarnings ++ secondarywarnings satisfy conf = NamedConf { confDomain = domain - , confType = Master + , confDnsServerType = Master , confFile = zonefile , confMasters = [] + , confAllowTransfer = nub $ + concatMap (\h -> hostAddresses h hosts) $ + secondaries ++ nssecondaries , confLines = [] } + secondaries = otherServers Secondary hosts domain + secondarywarnings = map (\h -> "No IP address defined for DNS seconary " ++ h) $ + filter (\h -> null (hostAddresses h hosts)) secondaries + nssecondaries = mapMaybe (domainHostName <=< getNS) rootRecords + rootRecords = map snd $ + filter (\(d, _r) -> d == RootDomain || d == AbsDomain domain) rs needupdate = do v <- readZonePropellorFile zonefile return $ case v of @@ -86,12 +106,7 @@ primary hosts domain soa rs = RevertableProperty setup cleanup -- Note that if a host is declared to be a primary and a secondary dns -- server for the same domain, the primary server config always wins. secondary :: [Host] -> Domain -> RevertableProperty -secondary hosts domain = secondaryFor masters hosts domain - where - masters = M.keys $ M.filter ismaster $ hostAttrMap hosts - ismaster attr = case M.lookup domain (_namedconf attr) of - Nothing -> False - Just conf -> confType conf == Master && confDomain conf == domain +secondary hosts domain = secondaryFor (otherServers Master hosts domain) hosts domain -- | This variant is useful if the primary server does not have its DNS -- configured via propellor. @@ -105,12 +120,22 @@ secondaryFor masters hosts domain = RevertableProperty setup cleanup desc = "dns secondary for " ++ domain conf = NamedConf { confDomain = domain - , confType = Secondary + , confDnsServerType = Secondary , confFile = "db." ++ domain , confMasters = concatMap (\m -> hostAddresses m hosts) masters - , confLines = ["allow-transfer { }"] + , confAllowTransfer = [] + , confLines = [] } +otherServers :: DnsServerType -> [Host] -> Domain -> [HostName] +otherServers wantedtype hosts domain = + M.keys $ M.filter wanted $ hostAttrMap hosts + where + wanted attr = case M.lookup domain (_namedconf attr) of + Nothing -> False + Just conf -> confDnsServerType conf == wantedtype + && confDomain conf == domain + -- | Rewrites the whole named.conf.local file to serve the zones -- configured by `primary` and `secondary`, and ensures that bind9 is -- running. @@ -130,20 +155,26 @@ confStanza :: NamedConf -> [Line] confStanza c = [ "// automatically generated by propellor" , "zone \"" ++ confDomain c ++ "\" {" - , cfgline "type" (if confType c == Master then "master" else "slave") + , cfgline "type" (if confDnsServerType c == Master then "master" else "slave") , cfgline "file" ("\"" ++ confFile c ++ "\"") ] ++ - (if null (confMasters c) then [] else mastersblock) ++ + mastersblock ++ + allowtransferblock ++ (map (\l -> "\t" ++ l ++ ";") (confLines c)) ++ [ "};" , "" ] where cfgline f v = "\t" ++ f ++ " " ++ v ++ ";" - mastersblock = - [ "\tmasters {" ] ++ - (map (\ip -> "\t\t" ++ fromIPAddr ip ++ ";") (confMasters c)) ++ + ipblock name l = + [ "\t" ++ name ++ " {" ] ++ + (map (\ip -> "\t\t" ++ fromIPAddr ip ++ ";") l) ++ [ "\t};" ] + mastersblock + | null (confMasters c) = [] + | otherwise = ipblock "masters" (confMasters c) + -- an empty block prohibits any transfers + allowtransferblock = ipblock "allow-transfer" (confAllowTransfer c) namedConfFile :: FilePath namedConfFile = "/etc/bind/named.conf.local" diff --git a/Propellor/Types/Dns.hs b/Propellor/Types/Dns.hs index 9b2ad1e7..ba6a92dd 100644 --- a/Propellor/Types/Dns.hs +++ b/Propellor/Types/Dns.hs @@ -1,5 +1,7 @@ module Propellor.Types.Dns where +import Propellor.Types.OS (HostName) + import Data.Word type Domain = String @@ -14,14 +16,15 @@ fromIPAddr (IPv6 addr) = addr -- | Represents a bind 9 named.conf file. data NamedConf = NamedConf { confDomain :: Domain - , confType :: Type + , confDnsServerType :: DnsServerType , confFile :: FilePath , confMasters :: [IPAddr] + , confAllowTransfer :: [IPAddr] , confLines :: [String] } deriving (Show, Eq, Ord) -data Type = Master | Secondary +data DnsServerType = Master | Secondary deriving (Show, Eq, Ord) -- | Represents a bind 9 zone file. @@ -66,6 +69,10 @@ getCNAME :: Record -> Maybe BindDomain getCNAME (CNAME d) = Just d getCNAME _ = Nothing +getNS :: Record -> Maybe BindDomain +getNS (NS d) = Just d +getNS _ = Nothing + -- | Bind serial numbers are unsigned, 32 bit integers. type SerialNumber = Word32 @@ -78,3 +85,8 @@ type SerialNumber = Word32 -- to add nameservers, MX's, etc to a domain. data BindDomain = RelDomain Domain | AbsDomain Domain | RootDomain deriving (Read, Show, Eq, Ord) + +domainHostName :: BindDomain -> Maybe HostName +domainHostName (RelDomain d) = Just d +domainHostName (AbsDomain d) = Just d +domainHostName RootDomain = Nothing |
