better serial number offsets
This commit is contained in:
parent
80caa6c09d
commit
8e22065def
|
@ -3,12 +3,10 @@ module Propellor.Property.Dns (
|
||||||
secondary,
|
secondary,
|
||||||
servingZones,
|
servingZones,
|
||||||
mkSOA,
|
mkSOA,
|
||||||
nextSerialNumber,
|
|
||||||
incrSerialNumber,
|
|
||||||
currentSerialNumber,
|
|
||||||
writeZoneFile,
|
writeZoneFile,
|
||||||
genZoneFile,
|
nextSerialNumber,
|
||||||
genSOA,
|
adjustSerialNumber,
|
||||||
|
serialNumberOffset,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Propellor
|
import Propellor
|
||||||
|
@ -19,7 +17,6 @@ import qualified Propellor.Property.Service as Service
|
||||||
import Utility.Applicative
|
import Utility.Applicative
|
||||||
|
|
||||||
import Data.List
|
import Data.List
|
||||||
import Data.Time.Clock.POSIX
|
|
||||||
|
|
||||||
namedconf :: FilePath
|
namedconf :: FilePath
|
||||||
namedconf = "/etc/bind/named.conf.local"
|
namedconf = "/etc/bind/named.conf.local"
|
||||||
|
@ -64,10 +61,18 @@ servingZones zs = hasContent namedconf (concatMap confStanza zs)
|
||||||
`onChange` Service.reloaded "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.
|
||||||
mkSOA :: Domain -> [Record] -> SOA
|
--
|
||||||
mkSOA d rs = SOA
|
-- The SerialNumber can be whatever serial number was used by the domain
|
||||||
|
-- before propellor started managing it. Or 0 if the domain has only ever
|
||||||
|
-- been managed by propellor.
|
||||||
|
--
|
||||||
|
-- You do not need to increment the SerialNumber when making changes!
|
||||||
|
-- Propellor will automatically add the number of commits in the git
|
||||||
|
-- repository to the SerialNumber.
|
||||||
|
mkSOA :: Domain -> SerialNumber -> [Record] -> SOA
|
||||||
|
mkSOA d sn rs = SOA
|
||||||
{ sDomain = AbsDomain d
|
{ sDomain = AbsDomain d
|
||||||
, sSerial = 1
|
, sSerial = sn
|
||||||
, sRefresh = hours 4
|
, sRefresh = hours 4
|
||||||
, sRetry = hours 1
|
, sRetry = hours 1
|
||||||
, sExpire = 2419200 -- 4 weeks
|
, sExpire = 2419200 -- 4 weeks
|
||||||
|
@ -102,47 +107,33 @@ rValue (TXT s) = [q] ++ filter (/= q) s ++ [q]
|
||||||
|
|
||||||
-- | Adjusts the serial number of the zone to
|
-- | Adjusts the serial number of the zone to
|
||||||
--
|
--
|
||||||
-- * Always be larger than the passed SerialNumber
|
|
||||||
-- * Always be larger than the serial number in the Zone record.
|
-- * Always be larger than the serial number in the Zone record.
|
||||||
|
-- * Always be larger than the passed SerialNumber
|
||||||
nextSerialNumber :: Zone -> SerialNumber -> Zone
|
nextSerialNumber :: Zone -> SerialNumber -> Zone
|
||||||
nextSerialNumber (Zone soa l) oldserial = Zone soa' l
|
nextSerialNumber z serial = adjustSerialNumber z $ \sn -> succ $ max sn serial
|
||||||
where
|
|
||||||
soa' = soa { sSerial = succ $ max (sSerial soa) oldserial }
|
|
||||||
|
|
||||||
incrSerialNumber :: Zone -> Zone
|
adjustSerialNumber :: Zone -> (SerialNumber -> SerialNumber) -> Zone
|
||||||
incrSerialNumber (Zone soa l) = Zone soa' l
|
adjustSerialNumber (Zone soa l) f = Zone soa' l
|
||||||
where
|
where
|
||||||
soa' = soa { sSerial = succ (sSerial soa) }
|
soa' = soa { sSerial = f (sSerial soa) }
|
||||||
|
|
||||||
-- | Propellor uses a serial number derived from the current date and time.
|
-- | Count the number of git commits made to the current branch.
|
||||||
--
|
serialNumberOffset :: IO SerialNumber
|
||||||
-- This ensures that, even if zone files are being generated on
|
serialNumberOffset = fromIntegral . length . lines
|
||||||
-- multiple hosts, the serial numbers will not get out of sync between
|
<$> readProcess "git" ["log", "--pretty=%H"]
|
||||||
-- them.
|
|
||||||
--
|
|
||||||
-- Since serial numbers are limited to 32 bits, the number of seconds
|
|
||||||
-- since the epoch is divided by 5. This will work until the year 2650,
|
|
||||||
-- at which point this stupid limit had better have been increased to
|
|
||||||
-- 128 bits. If we didn't divide by 5, it would only work up to 2106!
|
|
||||||
--
|
|
||||||
-- Dividing by 5 means that this number only changes once every 5 seconds.
|
|
||||||
-- If propellor is running more often than once every 5 seconds, you're
|
|
||||||
-- doing something wrong.
|
|
||||||
currentSerialNumber :: IO SerialNumber
|
|
||||||
currentSerialNumber = calc <$> getPOSIXTime
|
|
||||||
where
|
|
||||||
calc t = floor (t / 5)
|
|
||||||
|
|
||||||
-- | Write a Zone out to a to a file.
|
-- | Write a Zone out to a to a file.
|
||||||
--
|
--
|
||||||
-- The serial number that is written to the file comes from larger of the
|
-- The serial number in the Zone automatically has the serialNumberOffset
|
||||||
-- Zone's SOA serial number, and the last serial number used in the file.
|
-- added to it. Also, just in case, the old serial number used in the zone
|
||||||
-- This ensures that serial number always increases, while also letting
|
-- file is checked, and if it is somehow larger, its succ is used.
|
||||||
-- a Zone contain an existing serial number, which may be quite large.
|
|
||||||
writeZoneFile :: Zone -> FilePath -> IO ()
|
writeZoneFile :: Zone -> FilePath -> IO ()
|
||||||
writeZoneFile z f = do
|
writeZoneFile z f = do
|
||||||
oldserial <- nextZoneFileSerialNumber f
|
oldserial <- oldZoneFileSerialNumber f
|
||||||
let z' = nextSerialNumber z oldserial
|
offset <- serialNumberOffset
|
||||||
|
let z' = nextSerialNumber
|
||||||
|
(adjustSerialNumber z (+ offset))
|
||||||
|
(succ oldserial)
|
||||||
writeFile f (genZoneFile z')
|
writeFile f (genZoneFile z')
|
||||||
writeZonePropellorFile f z'
|
writeZonePropellorFile f z'
|
||||||
|
|
||||||
|
@ -152,9 +143,8 @@ writeZoneFile z f = do
|
||||||
zonePropellorFile :: FilePath -> FilePath
|
zonePropellorFile :: FilePath -> FilePath
|
||||||
zonePropellorFile f = f ++ ".serial"
|
zonePropellorFile f = f ++ ".serial"
|
||||||
|
|
||||||
nextZoneFileSerialNumber :: FilePath -> IO SerialNumber
|
oldZoneFileSerialNumber :: FilePath -> IO SerialNumber
|
||||||
nextZoneFileSerialNumber = maybe 1 (sSerial . zSOA . incrSerialNumber)
|
oldZoneFileSerialNumber = maybe 0 (sSerial . zSOA) <$$> readZonePropellorFile
|
||||||
<$$> readZonePropellorFile
|
|
||||||
|
|
||||||
writeZonePropellorFile :: FilePath -> Zone -> IO ()
|
writeZonePropellorFile :: FilePath -> Zone -> IO ()
|
||||||
writeZonePropellorFile f z = writeFile (zonePropellorFile f) (show z)
|
writeZonePropellorFile f z = writeFile (zonePropellorFile f) (show z)
|
||||||
|
@ -210,3 +200,9 @@ genSOA soa = unlines $
|
||||||
com :: String -> String
|
com :: String -> String
|
||||||
com s = "; " ++ s
|
com s = "; " ++ s
|
||||||
|
|
||||||
|
-- | Generates a Zone for a particular Domain from the DNS properies of all
|
||||||
|
-- hosts that propellor knows about that are in that Domain.
|
||||||
|
genZone :: [Host] -> Domain -> SOA -> Zone
|
||||||
|
genZone hosts domain soa = Zone soa zhosts
|
||||||
|
where
|
||||||
|
zhosts = undefined -- TODO
|
||||||
|
|
|
@ -2,7 +2,7 @@ module Propellor.Types.Dns where
|
||||||
|
|
||||||
import Propellor.Types.OS (HostName)
|
import Propellor.Types.OS (HostName)
|
||||||
|
|
||||||
import Foreign.C.Types
|
import Data.Word
|
||||||
|
|
||||||
type Domain = String
|
type Domain = String
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ getIPAddr (Address addr) = Just addr
|
||||||
getIPAddr _ = Nothing
|
getIPAddr _ = Nothing
|
||||||
|
|
||||||
-- | Bind serial numbers are unsigned, 32 bit integers.
|
-- | Bind serial numbers are unsigned, 32 bit integers.
|
||||||
type SerialNumber = CInt
|
type SerialNumber = Word32
|
||||||
|
|
||||||
-- | Domains in the zone file must end with a period if they are absolute.
|
-- | Domains in the zone file must end with a period if they are absolute.
|
||||||
--
|
--
|
||||||
|
|
Loading…
Reference in New Issue