diff --git a/config-joey.hs b/config-joey.hs index fb90651..74647df 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -160,6 +160,9 @@ kite = standardSystemUnhardened "kite.kitenet.net" Unstable "amd64" -- Some users have zsh as their login shell. , "zsh" ] + + & Docker.configured + & Docker.garbageCollected `period` Daily diatom :: Host diatom = standardSystem "diatom.kitenet.net" (Stable "wheezy") "amd64" diff --git a/debian/changelog b/debian/changelog index c580b3b..804d54c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +propellor (0.9.2) UNRELEASED; urgency=medium + + * Added nginx module, contributed by FĂ©lix Sipma. + * Added firewall module, contributed by Arnaud Bailly. + + -- Joey Hess Thu, 30 Oct 2014 16:36:06 -0400 + propellor (0.9.1) unstable; urgency=medium * Docker: Add ability to control when containers restart. diff --git a/propellor.cabal b/propellor.cabal index 282a5e0..43f098a 100644 --- a/propellor.cabal +++ b/propellor.cabal @@ -78,10 +78,12 @@ Library Propellor.Property.Dns Propellor.Property.Docker Propellor.Property.File + Propellor.Property.Firewall Propellor.Property.Git Propellor.Property.Gpg Propellor.Property.Grub Propellor.Property.Network + Propellor.Property.Nginx Propellor.Property.Obnam Propellor.Property.OpenId Propellor.Property.Postfix diff --git a/src/Propellor/Property/Firewall.hs b/src/Propellor/Property/Firewall.hs new file mode 100644 index 0000000..b660207 --- /dev/null +++ b/src/Propellor/Property/Firewall.hs @@ -0,0 +1,91 @@ +-- |Properties for configuring firewall (iptables) rules +-- +-- Copyright 2014 Arnaud Bailly +-- License: BSD-2-Clause +module Propellor.Property.Firewall ( + rule, + installed, + Chain(..), + Target(..), + Proto(..), + Rules(..), + ConnectionState(..) +) where + +import Data.Monoid +import Data.Char +import Data.List + +import Propellor +import Utility.SafeCommand +import qualified Propellor.Property.Apt as Apt +import qualified Propellor.Property.Network as Network + +installed :: Property +installed = Apt.installed ["iptables"] + +rule :: Chain -> Target -> Rules -> Property +rule c t rs = property ("firewall rule: " <> show r) addIpTable + where + r = Rule c t rs + addIpTable = liftIO $ do + let args = toIpTable r + exist <- boolSystem "iptables" (chk args) + if exist + then return NoChange + else ifM (boolSystem "iptables" (add args)) + ( return MadeChange , return FailedChange) + add params = (Param "-A") : params + chk params = (Param "-C") : params + +toIpTable :: Rule -> [CommandParam] +toIpTable r = map Param $ + (show $ ruleChain r) : + (toIpTableArg (ruleRules r)) ++ [ "-j" , show $ ruleTarget r ] + +toIpTableArg :: Rules -> [String] +toIpTableArg Everything = [] +toIpTableArg (Proto proto) = ["-p", map toLower $ show proto] +toIpTableArg (Port port) = ["--dport", show port] +toIpTableArg (PortRange (f,t)) = ["--dport", show f ++ ":" ++ show t] +toIpTableArg (IFace iface) = ["-i", iface] +toIpTableArg (Ctstate states) = ["-m", "conntrack","--ctstate", concat $ intersperse "," (map show states)] +toIpTableArg (r :- r') = toIpTableArg r <> toIpTableArg r' + +data Rule = Rule + { ruleChain :: Chain + , ruleTarget :: Target + , ruleRules :: Rules + } deriving (Eq, Show, Read) + +data Chain = INPUT | OUTPUT | FORWARD + deriving (Eq,Show,Read) + +data Target = ACCEPT | REJECT | DROP | LOG + deriving (Eq,Show,Read) + +data Proto = TCP | UDP | ICMP + deriving (Eq,Show,Read) + +type Port = Int + +data ConnectionState = ESTABLISHED | RELATED | NEW | INVALID + deriving (Eq,Show,Read) + +data Rules + = Everything + | Proto Proto + -- ^There is actually some order dependency between proto and port so this should be a specific + -- data type with proto + ports + | Port Port + | PortRange (Port,Port) + | IFace Network.Interface + | Ctstate [ ConnectionState ] + | Rules :- Rules -- ^Combine two rules + deriving (Eq,Show,Read) + +infixl 0 :- + +instance Monoid Rules where + mempty = Everything + mappend = (:-) diff --git a/src/Propellor/Property/Nginx.hs b/src/Propellor/Property/Nginx.hs new file mode 100644 index 0000000..97792fc --- /dev/null +++ b/src/Propellor/Property/Nginx.hs @@ -0,0 +1,47 @@ +module Propellor.Property.Nginx where + +import Propellor +import qualified Propellor.Property.File as File +import qualified Propellor.Property.Apt as Apt +import qualified Propellor.Property.Service as Service + +type ConfigFile = [String] + +siteEnabled :: HostName -> ConfigFile -> RevertableProperty +siteEnabled hn cf = RevertableProperty enable disable + where + enable = trivial (cmdProperty "ln" ["-s", siteValRelativeCfg hn, siteVal hn]) + `describe` ("nginx site enabled " ++ hn) + `requires` siteAvailable hn cf + `requires` installed + `onChange` reloaded + disable = trivial $ + ("nginx site disabled " ++ hn) ==> + File.notPresent (siteCfg hn) + `onChange` cmdProperty "rm" [siteVal hn] + `requires` installed + `onChange` reloaded + +siteAvailable :: HostName -> ConfigFile -> Property +siteAvailable hn cf = ("nginx site available " ++ hn) ==> + siteCfg hn `File.hasContent` (comment : cf) + where + comment = "# deployed with propellor, do not modify" + +siteCfg :: HostName -> FilePath +siteCfg hn = "/etc/nginx/sites-available/" ++ hn + +siteVal :: HostName -> FilePath +siteVal hn = "/etc/nginx/sites-enabled/" ++ hn + +siteValRelativeCfg :: HostName -> FilePath +siteValRelativeCfg hn = "../sites-available/" ++ hn + +installed :: Property +installed = Apt.installed ["nginx"] + +restarted :: Property +restarted = Service.restarted "nginx" + +reloaded :: Property +reloaded = Service.reloaded "nginx"