propellor 0.4.0 → 0.5.0
raw patch · 15 files changed
+236/−185 lines, 15 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Propellor.Property.Dns: rootAddressesFrom :: [Host] -> HostName -> [Record]
- Propellor.Types.Dns: SOADomain :: BindDomain
- Propellor.Types.Dns: sRecord :: SOA -> [Record]
+ Propellor.Property.Dns: type WarningMessage = String
+ Propellor.Types: type SetAttr = Attr -> Attr
+ Propellor.Types.Dns: RootDomain :: BindDomain
- Propellor.Property.Dns: mkSOA :: Domain -> SerialNumber -> [Record] -> SOA
+ Propellor.Property.Dns: mkSOA :: Domain -> SerialNumber -> SOA
- Propellor.Property.Dns: primary :: [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> Property
+ Propellor.Property.Dns: primary :: [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> RevertableProperty
- Propellor.Property.Dns: secondary :: [Host] -> Domain -> Property
+ Propellor.Property.Dns: secondary :: [Host] -> Domain -> RevertableProperty
- Propellor.Property.Dns: secondaryFor :: [HostName] -> [Host] -> Domain -> Property
+ Propellor.Property.Dns: secondaryFor :: [HostName] -> [Host] -> Domain -> RevertableProperty
- Propellor.Types.Dns: SOA :: BindDomain -> SerialNumber -> Integer -> Integer -> Integer -> Integer -> [Record] -> SOA
+ Propellor.Types.Dns: SOA :: BindDomain -> SerialNumber -> Integer -> Integer -> Integer -> Integer -> SOA
Files
- CHANGELOG +11/−0
- Propellor/Attr.hs +1/−1
- Propellor/Property/Apt.hs +13/−1
- Propellor/Property/Dns.hs +65/−62
- Propellor/Types.hs +2/−1
- Propellor/Types/Dns.hs +3/−4
- README.md +25/−61
- TODO +0/−26
- config-joey.hs +20/−15
- config-simple.hs +4/−5
- config.hs +4/−5
- debian/changelog +11/−0
- debian/rules +5/−1
- doc/README.mdwn +69/−0
- propellor.cabal +3/−3
CHANGELOG view
@@ -1,3 +1,14 @@+propellor (0.5.0) unstable; urgency=medium++ * Removed root domain records from SOA. Instead, use RootDomain+ when calling Dns.primary.+ * Dns primary and secondary properties are now revertable.+ * When unattendedUpgrades is enabled on an Unstable or Testing system,+ configure it to allow the upgrades.+ * New website, https://propellor.branchable.com/++ -- Joey Hess <joeyh@debian.org> Sat, 19 Apr 2014 17:38:02 -0400+ propellor (0.4.0) unstable; urgency=medium * Propellor can configure primary DNS servers, including generating
Propellor/Attr.hs view
@@ -43,7 +43,7 @@ -- | Indicates another name for the host in the DNS. alias :: Domain -> Property-alias domain = pureAttrProperty ("aka " ++ domain)+alias domain = pureAttrProperty ("alias " ++ domain) (addDNS $ CNAME $ AbsDomain domain) addDNS :: Record -> SetAttr
Propellor/Property/Apt.hs view
@@ -192,7 +192,9 @@ unattendedUpgrades :: RevertableProperty unattendedUpgrades = RevertableProperty enable disable where- enable = setup True `before` Service.running "cron"+ enable = setup True+ `before` Service.running "cron"+ `before` configure disable = setup False setup enabled = (if enabled then installed else removed) ["unattended-upgrades"]@@ -203,6 +205,16 @@ v | enabled = "true" | otherwise = "false"+ + configure = withOS "unattended upgrades configured" $ \o ->+ case o of+ -- the package defaults to only upgrading stable+ (Just (System (Debian suite) _))+ | not (isStable suite) -> ensureProperty $+ "/etc/apt/apt.conf.d/50unattended-upgrades"+ `File.containsLine`+ ("\t\"o=Debian,a="++showSuite suite++"\";")+ _ -> noChange -- | Preseeds debconf values and reconfigures the package so it takes -- effect.
Propellor/Property/Dns.hs view
@@ -4,11 +4,11 @@ secondary, secondaryFor, mkSOA,- rootAddressesFrom, writeZoneFile, nextSerialNumber, adjustSerialNumber, serialNumberOffset,+ WarningMessage, genZone, ) where @@ -36,14 +36,22 @@ -- 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` servingZones- `onChange` Service.reloaded "bind9"+-- The [(BindDomain, Record)] list can be used for additional records+-- that cannot be configured elsewhere. This often includes NS records,+-- TXT records and perhaps CNAMEs pointing at hosts that propellor does+-- not control.+primary :: [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> RevertableProperty+primary hosts domain soa rs = RevertableProperty setup cleanup where+ setup = withwarnings (check needupdate baseprop)+ `requires` servingZones+ `onChange` Service.reloaded "bind9"+ cleanup = check (doesFileExist zonefile) $+ property ("removed dns primary for " ++ domain)+ (makeChange $ removeZoneFile zonefile)+ `requires` namedConfWritten+ `onChange` Service.reloaded "bind9"+ (partialzone, warnings) = genZone hosts domain soa zone = partialzone { zHosts = zHosts partialzone ++ rs } zonefile = "/etc/bind/propellor/db." ++ domain@@ -77,7 +85,7 @@ -- -- 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 -> Property+secondary :: [Host] -> Domain -> RevertableProperty secondary hosts domain = secondaryFor masters hosts domain where masters = M.keys $ M.filter ismaster $ hostAttrMap hosts@@ -87,10 +95,13 @@ -- | This variant is useful if the primary server does not have its DNS -- configured via propellor.-secondaryFor :: [HostName] -> [Host] -> Domain -> Property-secondaryFor masters hosts domain = pureAttrProperty desc (addNamedConf conf)- `requires` servingZones+secondaryFor :: [HostName] -> [Host] -> Domain -> RevertableProperty+secondaryFor masters hosts domain = RevertableProperty setup cleanup where+ setup = pureAttrProperty desc (addNamedConf conf)+ `requires` servingZones+ cleanup = namedConfWritten+ desc = "dns secondary for " ++ domain conf = NamedConf { confDomain = domain@@ -104,16 +115,17 @@ -- configured by `primary` and `secondary`, and ensures that bind9 is -- running. servingZones :: Property-servingZones = property "serving configured dns zones" go+servingZones = namedConfWritten `requires` Apt.serviceInstalledRunning "bind9" `onChange` Service.reloaded "bind9"- where- go = do- zs <- getNamedConf- ensureProperty $- hasContent namedConfFile $- concatMap confStanza $ M.elems zs +namedConfWritten :: Property+namedConfWritten = property "named.conf configured" $ do+ zs <- getNamedConf+ ensureProperty $+ hasContent namedConfFile $+ concatMap confStanza $ M.elems zs+ confStanza :: NamedConf -> [Line] confStanza c = [ "// automatically generated by propellor"@@ -149,29 +161,22 @@ -- 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.------ Handy trick: You don't need to list IPAddrs in the [Record],--- just make some Host sets its `alias` to the root of domain.-mkSOA :: Domain -> SerialNumber -> [Record] -> SOA-mkSOA d sn rs = SOA+mkSOA :: Domain -> SerialNumber -> SOA+mkSOA d sn = SOA { sDomain = AbsDomain d , sSerial = sn , sRefresh = hours 4 , sRetry = hours 1 , sExpire = 2419200 -- 4 weeks , sNegativeCacheTTL = hours 8- , sRecord = rs } where hours n = n * 60 * 60 -rootAddressesFrom :: [Host] -> HostName -> [Record]-rootAddressesFrom hosts hn = map Address (hostAddresses hn hosts)- dValue :: BindDomain -> String dValue (RelDomain d) = d dValue (AbsDomain d) = d ++ "."-dValue (SOADomain) = "@"+dValue (RootDomain) = "@" rField :: Record -> String rField (Address (IPv4 _)) = "A"@@ -198,10 +203,9 @@ where q = '"' --- | Adjusts the serial number of the zone to ------ * Always be larger than the serial number in the Zone record.--- * Always be larger than the passed SerialNumber+-- | Adjusts the serial number of the zone to always be larger+-- than the serial number in the Zone record,+-- and always be larger than the passed SerialNumber. nextSerialNumber :: Zone -> SerialNumber -> Zone nextSerialNumber z serial = adjustSerialNumber z $ \sn -> succ $ max sn serial @@ -231,6 +235,11 @@ writeFile f (genZoneFile z') writeZonePropellorFile f z' +removeZoneFile :: FilePath -> IO ()+removeZoneFile f = do+ nukeFile f+ nukeFile (zonePropellorFile f)+ -- | Next to the zone file, is a ".propellor" file, which contains -- the serialized Zone. This saves the bother of parsing -- the horrible bind zone file format.@@ -250,43 +259,37 @@ -- | Generating a zone file. genZoneFile :: Zone -> String genZoneFile (Zone zdomain soa rs) = unlines $- header : genSOA zdomain soa ++ map genr rs+ header : genSOA soa ++ map (genRecord zdomain) rs where header = com $ "BIND zone file for " ++ zdomain ++ ". Generated by propellor, do not edit." - genr (d, r) = genRecord zdomain (Just d, r)--genRecord :: Domain -> (Maybe BindDomain, Record) -> String-genRecord zdomain (mdomain, record) = intercalate "\t"- [ hn+genRecord :: Domain -> (BindDomain, Record) -> String+genRecord zdomain (domain, record) = intercalate "\t"+ [ domainHost zdomain domain , "IN" , rField record , rValue record ]- where- hn = maybe "" (domainHost zdomain) mdomain -genSOA :: Domain -> SOA -> [String]-genSOA zdomain soa =- header ++ map (genRecord zdomain) (zip (repeat Nothing) (sRecord soa))- where- header =- -- "@ IN SOA ns1.example.com. root ("- [ intercalate "\t"- [ dValue SOADomain - , "IN"- , "SOA"- , dValue (sDomain soa)- , "root"- , "("- ]- , headerline sSerial "Serial"- , headerline sRefresh "Refresh"- , headerline sRetry "Retry"- , headerline sExpire "Expire"- , headerline sNegativeCacheTTL "Negative Cache TTL"- , inheader ")"+genSOA :: SOA -> [String]+genSOA soa = + -- "@ IN SOA ns1.example.com. root ("+ [ intercalate "\t"+ [ dValue RootDomain + , "IN"+ , "SOA"+ , dValue (sDomain soa)+ , "root"+ , "(" ]+ , headerline sSerial "Serial"+ , headerline sRefresh "Refresh"+ , headerline sRetry "Retry"+ , headerline sExpire "Expire"+ , headerline sNegativeCacheTTL "Negative Cache TTL"+ , inheader ")"+ ]+ where headerline r comment = inheader $ show (r soa) ++ "\t\t" ++ com comment inheader l = "\t\t\t" ++ l @@ -361,7 +364,7 @@ -- suitable for using in a zone file. domainHost :: Domain -> BindDomain -> String domainHost _ (RelDomain d) = d-domainHost _ SOADomain = "@"+domainHost _ RootDomain = "@" domainHost base (AbsDomain d) | dotbase `isSuffixOf` d = take (length d - length dotbase) d | base == d = "@"
Propellor/Types.hs view
@@ -5,6 +5,7 @@ module Propellor.Types ( Host(..) , Attr+ , SetAttr , Propellor(..) , Property(..) , RevertableProperty(..)@@ -56,7 +57,7 @@ , propertySatisfy :: Propellor Result -- ^ must be idempotent; may run repeatedly , propertyAttr :: SetAttr- -- ^ a property can affect the overall Attr+ -- ^ a property can set an Attr on the host that has the property. } -- | A property that can be reverted.
Propellor/Types/Dns.hs view
@@ -43,8 +43,6 @@ , sRetry :: Integer , sExpire :: Integer , sNegativeCacheTTL :: Integer- , sRecord :: [Record]- -- ^ Records for the root of the domain. Typically NS, A, TXT } deriving (Read, Show, Eq) @@ -76,6 +74,7 @@ -- Let's use a type to keep absolute domains straight from relative -- domains. ----- The SOADomain refers to the root SOA record.-data BindDomain = RelDomain Domain | AbsDomain Domain | SOADomain+-- The RootDomain refers to the top level of the domain, so can be used+-- to add nameservers, MX's, etc to a domain.+data BindDomain = RelDomain Domain | AbsDomain Domain | RootDomain deriving (Read, Show, Eq, Ord)
README.md view
@@ -1,31 +1,36 @@-This is a configuration management system using Haskell and Git.--Propellor enures that the system it's run against satisfies a list of-properties, taking action as necessary when a property is not yet met.+[Propellor](https://propellor.branchable.com/) is a+configuration management system using Haskell and Git.+Each system has a list of properties, which Propellor ensures+are satisfied. Propellor is configured via a git repository, which typically lives-in ~/.propellor/. The git repository contains a config.hs file,-and also the entire source code to propellor.--You typically want to have the repository checked out on a laptop, in order-to make changes and push them out to hosts. Each host will also have a-clone of the repository, and in that clone "make" can be used to build and-run propellor. This can be done by a cron job (which propellor can set up),-or a remote host can be triggered to update by running propellor on your-laptop: propellor --spin $host+in `~/.propellor/` on your development machine. Propellor clones the+repository to each host it manages, in a +[secure](http://propellor.branchable.com/security/) way. -Properties are defined using Haskell. Edit config.hs to get started.-For API documentation, see <http://hackage.haskell.org/package/propellor/>+Properties are defined using Haskell. Edit `~/.propellor/config.hs`+to get started. There is fairly complete +[API documentation](http://hackage.haskell.org/package/propellor/),+which includes many built-in Properties for dealing with+[Apt](http://hackage.haskell.org/package/propellor-0.4.0/docs/Propellor-Property-Apt.html)+and+[Apache](http://hackage.haskell.org/package/propellor-0.4.0/docs/Propellor-Property-Apache.html)+,+[Cron](http://hackage.haskell.org/package/propellor-0.4.0/docs/Propellor-Property-Cron.html)+and+[Commands](http://hackage.haskell.org/package/propellor-0.4.0/docs/Propellor-Property-Cmd.html)+,+[Dns](http://hackage.haskell.org/package/propellor-0.4.0/docs/Propellor-Property-Dns.html)+and+[Docker](http://hackage.haskell.org/package/propellor-0.4.0/docs/Propellor-Property-Docker.html), etc. There is no special language as used in puppet, chef, ansible, etc.. just the full power of Haskell. Hopefully that power can be put to good use in making declarative properties that are powerful, nicely idempotent, and-easy to adapt to a system's special needs.+easy to adapt to a system's special needs! -Also avoided is any form of node classification. Ie, which hosts are part-of which classes and share which configuration. It might be nice to use-reclass[1], but then again a host is configured using simply haskell code,-and so it's easy to factor out things like classes of hosts as desired.+If using Haskell to configure Propellor seems intimidating,+see [configuration for the Haskell newbie](https://propellor.branchable.com/haskell_newbie/). ## quick start @@ -58,48 +63,7 @@ hosts. 10. Write some neat new properties and send patches to <propellor@joeyh.name>! -## security--Propellor's security model is that the hosts it's used to deploy are-untrusted, and that the central git repository server is untrusted too.--The only trusted machine is the laptop where you run `propellor --spin`-to connect to a remote host. And that one only because you have a ssh key-or login password to the host.--Since the hosts propellor deploys are not trusted by the central git-repository, they have to use git:// or http:// to pull from the central-git repository, rather than ssh://. --So, to avoid a MITM attack, propellor checks that any commit it fetches-from origin is gpg signed by a trusted gpg key, and refuses to deploy it-otherwise.--That is only done when privdata/keyring.gpg exists. To set it up:-- gpg --gen-key # only if you don't already have a gpg key- propellor --add-key $MYKEYID--In order to be secure from the beginning, when `propellor --spin` is used-to bootstrap propellor on a new host, it transfers the local git repositry-to the remote host over ssh. After that, the remote host knows the-gpg key, and will use it to verify git fetches.--Since the propoellor git repository is public, you can't store-in cleartext private data such as passwords, ssh private keys, etc.--Instead, `propellor --spin $host` looks for a-`~/.propellor/privdata/$host.gpg` file and if found decrypts it and sends-it to the remote host using ssh. This lets a remote host know its own-private data, without seeing all the rest.--To securely store private data, use: `propellor --set $host $field`-The field name will be something like 'Password "root"'; see PrivData.hs-for available fields.- ## debugging Set `PROPELLOR_DEBUG=1` to make propellor print out all the commands it runs and any other debug messages that Properties choose to emit.--[1] http://reclass.pantsfullofunix.net/
− TODO
@@ -1,26 +0,0 @@-* Need a way to run an action when a property changes, but only- run it once for the whole. For example, may want to restart apache,- but only once despite many config changes being made to satisfy- properties. onChange is a poor substitute.-* Display of docker container properties is a bit wonky. It always- says they are unchanged even when they changed and triggered a- reprovision.-* Should properties be a tree rather than a list?-* Need a way for a dns server host to look at the properties of - the other hosts and generate a zone file. For example, mapping- openid.kitenet.net to a CNAME to clam.kitenet.net, which is where- the docker container for that service is located. Moving containers- to a different host, or duplicating a container on multiple hosts- would then update DNS too-* There is no way for a property of a docker container to require- some property be met outside the container. For example, some servers- need ntp installed for a good date source.-* Docking a container in a host should add to the host any cnames that- are assigned to the container.-* Either `Ssh.hostKey` should set the sshPubKey attr- (which seems hard, as attrs need to be able to be calculated without- running any IO code, and here IO is needed along with decrypting the- PrivData..), or the public key should not be stored in- the PrivData, and instead configured using the attr.- Getting the ssh host key into the attr will allow automatically- exporting it via DNS (SSHFP record)
config-joey.hs view
@@ -1,4 +1,4 @@--- | This is the live config file used by propellor's author.+-- This is the live config file used by propellor's author. import Propellor import Propellor.CmdLine@@ -23,7 +23,10 @@ import qualified Propellor.Property.SiteSpecific.GitAnnexBuilder as GitAnnexBuilder import qualified Propellor.Property.SiteSpecific.JoeySites as JoeySites +main :: IO ()+main = defaultMain hosts + -- _ ______`| ,-.__ {- Propellor -- / \___-=O`/|O`/__| (____.' Deployed -} -- \ / | / ) _.-"-._@@ -61,6 +64,9 @@ -- I'd rather this were on diatom, but it needs unstable. & alias "kgb.kitenet.net" & JoeySites.kgbServer+ + & alias "ns9.kitenet.net"+ & myDnsSecondary & Docker.garbageCollected `period` Daily & Apt.installed ["git-annex", "mtr", "screen"]@@ -122,17 +128,17 @@ & alias "resources.olduse.net" & JoeySites.oldUseNetServer hosts + & alias "ns2.kitenet.net" & myDnsSecondary & 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") ]+ (Dns.mkSOA "ns2.kitenet.net" 100)+ [ (RootDomain, NS $ AbsDomain "ns2.kitenet.net")+ , (RootDomain, NS $ AbsDomain "ns6.gandi.net")+ , (RootDomain, NS $ AbsDomain "ns9.kitenet.net")+ , (RootDomain, MX 0 $ AbsDomain "kitenet.net")+ , (RootDomain, TXT "v=spf1 a -all")+ , (RelDomain "article", CNAME $ AbsDomain "virgil.koldfront.dk")+ ] & Apt.installed ["ntop"] @@ -223,7 +229,7 @@ where system = System (Debian suite) arch --- | Docker images I prefer to use.+-- Docker images I prefer to use. image :: System -> Docker.Image image (System (Debian Unstable) arch) = "joeyh/debian-unstable-" ++ arch image (System (Debian Stable) arch) = "joeyh/debian-stable-" ++ arch@@ -246,7 +252,7 @@ ] myDnsSecondary :: Property-myDnsSecondary = propertyList "dns secondary for all my domains"+myDnsSecondary = propertyList "dns secondary for all my domains" $ map toProp [ Dns.secondaryFor wren hosts "kitenet.net" , Dns.secondaryFor wren hosts "joeyh.name" , Dns.secondaryFor wren hosts "ikiwiki.info"@@ -257,11 +263,8 @@ wren = ["wren.kitenet.net"] branchable = ["branchable.com"] -main :: IO ()-main = defaultMain hosts - -- o -- ___ o o {-----\ / o \ ___o o@@ -287,6 +290,8 @@ & ipv4 "80.68.85.49" & ipv6 "2001:41c8:125:49::10" & alias "kite.kitenet.net"+ & alias "kitenet.net"+ & alias "ns1.kitenet.net" , host "branchable.com" & ipv4 "66.228.46.55" & ipv6 "2600:3c03::f03c:91ff:fedf:c0e5"
config-simple.hs view
@@ -1,4 +1,4 @@--- | This is the main configuration file for Propellor, and is used to build+-- This is the main configuration file for Propellor, and is used to build -- the propellor program. import Propellor@@ -16,13 +16,15 @@ --import qualified Propellor.Property.Tor as Tor import qualified Propellor.Property.Docker as Docker +main :: IO ()+main = defaultMain hosts+ -- The hosts propellor knows about. -- Edit this to configure propellor! hosts :: [Host] hosts = [ host "mybox.example.com" & Apt.stdSourcesList Unstable- `onChange` Apt.upgrade & Apt.unattendedUpgrades & Apt.installed ["etckeeper"] & Apt.installed ["ssh"]@@ -42,6 +44,3 @@ -- add more hosts here... --, host "foo.example.com" = ... ]--main :: IO ()-main = defaultMain hosts
config.hs view
@@ -1,4 +1,4 @@--- | This is the main configuration file for Propellor, and is used to build+-- This is the main configuration file for Propellor, and is used to build -- the propellor program. import Propellor@@ -16,13 +16,15 @@ --import qualified Propellor.Property.Tor as Tor import qualified Propellor.Property.Docker as Docker +main :: IO ()+main = defaultMain hosts+ -- The hosts propellor knows about. -- Edit this to configure propellor! hosts :: [Host] hosts = [ host "mybox.example.com" & Apt.stdSourcesList Unstable- `onChange` Apt.upgrade & Apt.unattendedUpgrades & Apt.installed ["etckeeper"] & Apt.installed ["ssh"]@@ -42,6 +44,3 @@ -- add more hosts here... --, host "foo.example.com" = ... ]--main :: IO ()-main = defaultMain hosts
debian/changelog view
@@ -1,3 +1,14 @@+propellor (0.5.0) unstable; urgency=medium++ * Removed root domain records from SOA. Instead, use RootDomain+ when calling Dns.primary.+ * Dns primary and secondary properties are now revertable.+ * When unattendedUpgrades is enabled on an Unstable or Testing system,+ configure it to allow the upgrades.+ * New website, https://propellor.branchable.com/++ -- Joey Hess <joeyh@debian.org> Sat, 19 Apr 2014 17:38:02 -0400+ propellor (0.4.0) unstable; urgency=medium * Propellor can configure primary DNS servers, including generating
debian/rules view
@@ -9,6 +9,10 @@ override_dh_auto_build: $(MAKE) build override_dh_installdocs:- dh_installdocs README.md TODO+ dh_installdocs doc/README.mdwn override_dh_installman: dh_installman debian/propellor.1++# Not intended for use by anyone except the author.+announcedir:+ @echo ${HOME}/src/propellor/doc/news
+ doc/README.mdwn view
@@ -0,0 +1,69 @@+[Propellor](https://propellor.branchable.com/) is a+configuration management system using Haskell and Git.+Each system has a list of properties, which Propellor ensures+are satisfied.++Propellor is configured via a git repository, which typically lives+in `~/.propellor/` on your development machine. Propellor clones the+repository to each host it manages, in a +[secure](http://propellor.branchable.com/security/) way.++Properties are defined using Haskell. Edit `~/.propellor/config.hs`+to get started. There is fairly complete +[API documentation](http://hackage.haskell.org/package/propellor/),+which includes many built-in Properties for dealing with+[Apt](http://hackage.haskell.org/package/propellor-0.4.0/docs/Propellor-Property-Apt.html)+and+[Apache](http://hackage.haskell.org/package/propellor-0.4.0/docs/Propellor-Property-Apache.html)+,+[Cron](http://hackage.haskell.org/package/propellor-0.4.0/docs/Propellor-Property-Cron.html)+and+[Commands](http://hackage.haskell.org/package/propellor-0.4.0/docs/Propellor-Property-Cmd.html)+,+[Dns](http://hackage.haskell.org/package/propellor-0.4.0/docs/Propellor-Property-Dns.html)+and+[Docker](http://hackage.haskell.org/package/propellor-0.4.0/docs/Propellor-Property-Docker.html), etc.++There is no special language as used in puppet, chef, ansible, etc.. just+the full power of Haskell. Hopefully that power can be put to good use in+making declarative properties that are powerful, nicely idempotent, and+easy to adapt to a system's special needs!++If using Haskell to configure Propellor seems intimidating,+see [configuration for the Haskell newbie](https://propellor.branchable.com/haskell_newbie/).++## quick start++1. Get propellor installed+ `cabal install propellor`+ or+ `apt-get install propellor`+2. Run propellor for the first time. It will set up a `~/.propellor/` git+ repository for you.+3. `cd ~/.propellor/`; use git to push the repository to a central+ server (github, or your own git server). Configure that central+ server as the origin remote of the repository.+4. If you don't have a gpg private key, generate one: `gpg --gen-key`+5. Run: `propellor --add-key $KEYID`+6. Edit `~/.propellor/config.hs`, and add a host you want to manage.+ You can start by not adding any properties, or only a few.+7. Pick a host and run: `propellor --spin $HOST`+8. Now you have a simple propellor deployment, but it doesn't do+ much to the host yet, besides installing propellor.++ So, edit `~/.propellor/config.hs` to configure the host (maybe+ start with a few simple properties), and re-run step 7.+ Repeat until happy and move on to the next host. :)+9. To move beyond manually running `propellor --spin` against hosts+ when you change their properties, add a property to your hosts+ like: `Cron.runPropellor "30 * * * *"`+ + Now they'll automatically update every 30 minutes, and you can+ `git commit -S` and `git push` changes that affect any number of+ hosts.+10. Write some neat new properties and send patches to <propellor@joeyh.name>!++## debugging++Set `PROPELLOR_DEBUG=1` to make propellor print out all the commands it runs+and any other debug messages that Properties choose to emit.
propellor.cabal view
@@ -1,5 +1,5 @@ Name: propellor-Version: 0.4.0+Version: 0.5.0 Cabal-Version: >= 1.6 License: GPL Maintainer: Joey Hess <joey@kitenet.net>@@ -8,11 +8,11 @@ Copyright: 2014 Joey Hess License-File: GPL Build-Type: Simple-Homepage: http://joeyh.name/code/propellor/+Homepage: https://propellor.branchable.com/ Category: Utility Extra-Source-Files: README.md- TODO+ doc/README.mdwn CHANGELOG Makefile config-simple.hs