packages feed

propellor 3.4.1 → 4.0.0

raw patch · 34 files changed

+341/−142 lines, 34 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Propellor.Property: applyToList :: (Foldable t, Functor t, Combines p p, p ~ CombinedType p p) => (b -> p) -> t b -> p
- Propellor.Types.Info: data Info
- Propellor.Types.Info: propagatableInfo :: Info -> Info
+ Propellor.Container: normalContainerInfo :: PropagateInfo -> Bool
+ Propellor.Container: onlyPrivData :: PropagateInfo -> Bool
+ Propellor.Container: propagatableInfo :: (PropagateInfo -> Bool) -> Info -> Info
+ Propellor.Property.Apache: confEnabled :: String -> RevertableProperty DebianLike DebianLike
+ Propellor.Property.Chroot: hostChroot :: ChrootBootstrapper bootstrapper => Host -> bootstrapper -> FilePath -> Chroot
+ Propellor.Types: instance (GHC.Base.Monoid (Propellor.Types.Property setupmetatypes), GHC.Base.Monoid (Propellor.Types.Property undometatypes)) => GHC.Base.Monoid (Propellor.Types.RevertableProperty setupmetatypes undometatypes)
+ Propellor.Types: instance forall k (metatypes :: k). Propellor.Types.Singletons.SingI metatypes => GHC.Base.Monoid (Propellor.Types.Property (Propellor.Types.MetaTypes.MetaTypes metatypes))
+ Propellor.Types: property'' :: SingI metatypes => Desc -> Maybe (Propellor Result) -> Property (MetaTypes metatypes)
+ Propellor.Types.Info: Info :: [InfoEntry] -> Info
+ Propellor.Types.Info: PropagateInfo :: Bool -> PropagateInfo
+ Propellor.Types.Info: PropagatePrivData :: PropagateInfo
+ Propellor.Types.Info: [InfoEntry] :: (IsInfo v, Typeable v) => v -> InfoEntry
+ Propellor.Types.Info: data InfoEntry
+ Propellor.Types.Info: data PropagateInfo
+ Propellor.Types.Info: newtype Info
- Propellor: Property :: metatypes -> Desc -> (Propellor Result) -> Info -> [ChildProperty] -> Property metatypes
+ Propellor: Property :: metatypes -> Desc -> (Maybe (Propellor Result)) -> Info -> [ChildProperty] -> Property metatypes
- Propellor.Container: propagateContainer :: (IncludesInfo metatypes ~ True, IsContainer c) => String -> c -> Property metatypes -> Property metatypes
+ Propellor.Container: propagateContainer :: (IncludesInfo metatypes ~ True, IsContainer c) => String -> c -> (PropagateInfo -> Bool) -> Property metatypes -> Property metatypes
- Propellor.Property.Chroot: [Chroot] :: ChrootBootstrapper b => FilePath -> b -> Host -> Chroot
+ Propellor.Property.Chroot: [Chroot] :: ChrootBootstrapper b => FilePath -> b -> InfoPropagator -> Host -> Chroot
- Propellor.Property.Chroot: propagateChrootInfo :: Chroot -> Property Linux -> Property (HasInfo + Linux)
+ Propellor.Property.Chroot: propagateChrootInfo :: Chroot -> InfoPropagator
- Propellor.Property.Chroot: provisioned' :: (Property Linux -> Property (HasInfo + Linux)) -> Chroot -> Bool -> RevertableProperty (HasInfo + Linux) Linux
+ Propellor.Property.Chroot: provisioned' :: Chroot -> Bool -> RevertableProperty (HasInfo + Linux) Linux
- Propellor.Types: Property :: metatypes -> Desc -> (Propellor Result) -> Info -> [ChildProperty] -> Property metatypes
+ Propellor.Types: Property :: metatypes -> Desc -> (Maybe (Propellor Result)) -> Info -> [ChildProperty] -> Property metatypes
- Propellor.Types: type ResultCombiner = Propellor Result -> Propellor Result -> Propellor Result
+ Propellor.Types: type ResultCombiner = Maybe (Propellor Result) -> Maybe (Propellor Result) -> Maybe (Propellor Result)
- Propellor.Types.Core: ChildProperty :: Desc -> (Propellor Result) -> Info -> [ChildProperty] -> ChildProperty
+ Propellor.Types.Core: ChildProperty :: Desc -> (Maybe (Propellor Result)) -> Info -> [ChildProperty] -> ChildProperty
- Propellor.Types.Core: getSatisfy :: IsProp p => p -> Propellor Result
+ Propellor.Types.Core: getSatisfy :: IsProp p => p -> Maybe (Propellor Result)
- Propellor.Types.Info: propagateInfo :: IsInfo v => v -> Bool
+ Propellor.Types.Info: propagateInfo :: IsInfo v => v -> PropagateInfo

Files

CHANGELOG view
@@ -1,3 +1,36 @@+propellor (4.0.0) unstable; urgency=medium++  * Added Monoid instances for Property and RevertableProperty.+  * Removed applyToList. Instead, use mconcat. (API change)+    If you had:  applyToList accountFor [User "joey", User "root"]+    use instead: mconcat (map accountFor [User "joey", User "root"])+  * Makefile: Removed "run" target which was default target.+    "make" now only builds propellor, does not run it.+    Note that propellor 1.0.0 and earlier relied on this target for+    the Cron.runPropellor property's cronjob to work, so upgrading+    directly from 1.0.0 to 4.0.0 would break that cron job.+  * Remove make from propellor's dependency list; it's not used by+    propellor any longer.+  * Implemented hostChroot, as originally seen in my slides at+    Linux.Conf.Au 2017 in January. Now that it's not vaporware, it allows+    one Host to build a disk image that has all the properties of another+    Host.+  * DiskImage building properties used to propagate DNS info out from+    the chroot used to build the disk image to the Host. That is no longer+    done, since that chroot only exists as a side effect of the disk image+    creation and servers will not be running in it.+  * The IsInfo types class's propagateInfo function changed to use a+    PropagateInfo data type. (API change)+  * The action used to satisfy a property changed to Maybe (Propellor Result).+    When it is Nothing, propellor knows it can skip displaying the+    description of that property. This is mostly useful in the+    implementation of mempty. (API change)+  * The doNothing property is now simply mempty. The name was retained+    because it can be clearer than mempty in some contexts.+  * Added Apache.confEnabled.++ -- Joey Hess <id@joeyh.name>  Wed, 15 Mar 2017 15:46:42 -0400+ propellor (3.4.1) unstable; urgency=medium    * Fixed https url to propellor git repository.
Makefile view
@@ -1,11 +1,6 @@ CABAL?=cabal DATE := $(shell dpkg-parsechangelog 2>/dev/null | grep Date | cut -d " " -f2-) -# this target is provided (and is first) to keep old versions of the-# propellor cron job working, and will eventually be removed-run: build-	./propellor- build: tags propellor.1 dist/setup-config 	$(CABAL) build 	ln -sf dist/build/propellor-config/propellor-config propellor
README.md view
@@ -12,8 +12,8 @@ [components](http://propellor.branchable.com/components/) for details. -Properties are defined using Haskell. Edit `~/.propellor/config.hs`-to get started. There is fairly complete +Properties are defined using Haskell in the file `~/.propellor/config.hs`.+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/docs/Propellor-Property-Apt.html)
debian/changelog view
@@ -1,3 +1,36 @@+propellor (4.0.0) unstable; urgency=medium++  * Added Monoid instances for Property and RevertableProperty.+  * Removed applyToList. Instead, use mconcat. (API change)+    If you had:  applyToList accountFor [User "joey", User "root"]+    use instead: mconcat (map accountFor [User "joey", User "root"])+  * Makefile: Removed "run" target which was default target.+    "make" now only builds propellor, does not run it.+    Note that propellor 1.0.0 and earlier relied on this target for+    the Cron.runPropellor property's cronjob to work, so upgrading+    directly from 1.0.0 to 4.0.0 would break that cron job.+  * Remove make from propellor's dependency list; it's not used by+    propellor any longer.+  * Implemented hostChroot, as originally seen in my slides at+    Linux.Conf.Au 2017 in January. Now that it's not vaporware, it allows+    one Host to build a disk image that has all the properties of another+    Host.+  * DiskImage building properties used to propagate DNS info out from+    the chroot used to build the disk image to the Host. That is no longer+    done, since that chroot only exists as a side effect of the disk image+    creation and servers will not be running in it.+  * The IsInfo types class's propagateInfo function changed to use a+    PropagateInfo data type. (API change)+  * The action used to satisfy a property changed to Maybe (Propellor Result).+    When it is Nothing, propellor knows it can skip displaying the+    description of that property. This is mostly useful in the+    implementation of mempty. (API change)+  * The doNothing property is now simply mempty. The name was retained+    because it can be clearer than mempty in some contexts.+  * Added Apache.confEnabled.++ -- Joey Hess <id@joeyh.name>  Wed, 15 Mar 2017 15:46:42 -0400+ propellor (3.4.1) unstable; urgency=medium    * Fixed https url to propellor git repository.
debian/control view
@@ -44,7 +44,6 @@ 	libghc-text-dev, 	libghc-concurrent-output-dev, 	git,-	make, Description: property-based host configuration management in haskell  Propellor ensures that the system it's run in satisfies a list of  properties, taking action as necessary when a property is not yet met.
doc/README.mdwn view
@@ -12,8 +12,8 @@ [components](http://propellor.branchable.com/components/) for details. -Properties are defined using Haskell. Edit `~/.propellor/config.hs`-to get started. There is fairly complete +Properties are defined using Haskell in the file `~/.propellor/config.hs`.+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/docs/Propellor-Property-Apt.html)
joeyconfig.hs view
@@ -164,7 +164,7 @@ oyster = host "oyster.kitenet.net" $ props 	& standardSystem Unstable X86_64 		[ "Unreliable server. Anything here may be lost at any time!" ]-	& ipv4 "64.137.221.146"+	& ipv4 "45.62.245.55"  	& CloudAtCost.decruft 	& Ssh.hostKeys hostContext@@ -249,14 +249,17 @@ 	-- No hardware clock. 	& Apt.serviceInstalledRunning "ntp" +	-- Runs only on weekdays. 	& Systemd.nspawned (GitAnnexBuilder.autoBuilderContainer 		GitAnnexBuilder.armAutoBuilder-		Unstable ARMEL Nothing -		(Cron.Times "15 6 * * *") "22h")+		Unstable ARMEL Nothing weekends "23h")+	-- Runs only on weekends. 	& Systemd.nspawned (GitAnnexBuilder.autoBuilderContainer 		GitAnnexBuilder.stackAutoBuilder-		(Stable "jessie") ARMEL (Just "ancient")-		(Cron.Times "15 18 * * *") "22h")+		(Stable "jessie") ARMEL (Just "ancient") weekdays "23h")+  where+	weekdays = Cron.Times "15 6 * * 2-5"+	weekends = Cron.Times "15 6 * * 6-7"  -- This is not a complete description of kite, since it's a -- multiuser system with eg, user passwords that are not deployed
propellor.cabal view
@@ -1,5 +1,5 @@ Name: propellor-Version: 3.4.1+Version: 4.0.0 Cabal-Version: >= 1.8 License: BSD2 Maintainer: Joey Hess <id@joeyh.name>
src/Propellor/Bootstrap.hs view
@@ -94,7 +94,6 @@ 		, "libghc-exceptions-dev" 		, "libghc-stm-dev" 		, "libghc-text-dev"-		, "make" 		] 	fbsddeps = 		[ "gnupg"@@ -112,7 +111,6 @@ 		, "hs-exceptions" 		, "hs-stm" 		, "hs-text"-		, "gmake" 		] 	archlinuxdeps = 		[ "gnupg"@@ -131,7 +129,6 @@ 		, "haskell-exceptions" 		, "haskell-stm" 		, "haskell-text"-		, "make" 		]  installGitCommand :: Maybe System -> ShellCommand
src/Propellor/Container.hs view
@@ -51,15 +51,30 @@ 		) 	=> String 	-> c+	-> (PropagateInfo -> Bool) 	-> Property metatypes 	-> Property metatypes-propagateContainer containername c prop = prop+propagateContainer containername c wanted prop = prop 	`addChildren` map convert (containerProperties c)   where 	convert p = -		let n = property (getDesc p) (getSatisfy p) :: Property UnixLike+		let n = property'' (getDesc p) (getSatisfy p) :: Property UnixLike 		    n' = n 		    	`setInfoProperty` mapInfo (forceHostContext containername)-				(propagatableInfo (getInfo p))+				(propagatableInfo wanted (getInfo p)) 		   	`addChildren` map convert (getChildren p) 		in toChildProperty n'++-- | Filters out parts of the Info that should not propagate out of a+-- container.+propagatableInfo :: (PropagateInfo -> Bool) -> Info -> Info+propagatableInfo wanted (Info l) = Info $+	filter (\(InfoEntry a) -> wanted (propagateInfo a)) l++normalContainerInfo :: PropagateInfo -> Bool+normalContainerInfo PropagatePrivData = True+normalContainerInfo (PropagateInfo b) = b++onlyPrivData :: PropagateInfo -> Bool+onlyPrivData PropagatePrivData = True+onlyPrivData (PropagateInfo _) = False
src/Propellor/Engine.hs view
@@ -66,7 +66,9 @@ 	ensure [] rs = return rs 	ensure (p:ls) rs = do 		hn <- asks hostName-		r <- actionMessageOn hn (getDesc p) (catchPropellor $ getSatisfy p)+		r <- maybe (pure NoChange)+			(actionMessageOn hn (getDesc p) . catchPropellor)+			(getSatisfy p) 		ensure ls (r <> rs)  -- | Lifts an action into the context of a different host.
src/Propellor/EnsureProperty.hs view
@@ -46,7 +46,7 @@ 	=> OuterMetaTypesWitness outer 	-> Property (MetaTypes inner) 	-> Propellor Result-ensureProperty _ = catchPropellor . getSatisfy+ensureProperty _ = maybe (pure NoChange) catchPropellor . getSatisfy  -- The name of this was chosen to make type errors a bit more understandable. type family Cannot_ensureProperty_WithInfo (l :: [a]) :: Bool@@ -62,7 +62,7 @@ 	-> (OuterMetaTypesWitness metatypes -> Propellor Result) 	-> Property (MetaTypes metatypes) property' d a =-	let p = Property sing d (a (outerMetaTypesWitness p)) mempty mempty+	let p = Property sing d (Just (a (outerMetaTypesWitness p))) mempty mempty 	in p  -- | Used to provide the metatypes of a Property to calls to 
src/Propellor/PrivData.hs view
@@ -281,10 +281,10 @@ 	{ fromPrivInfo :: S.Set (PrivDataField, Maybe PrivDataSourceDesc, HostContext) } 	deriving (Eq, Ord, Show, Typeable, Monoid) --- PrivInfo is propagated out of containers, so that propellor can see which--- hosts need it.+-- PrivInfo always propagates out of containers, so that propellor+-- can see which hosts need it. instance IsInfo PrivInfo where-	propagateInfo _ = True+	propagateInfo _ = PropagatePrivData  -- | Sets the context of any privdata that uses HostContext to the -- provided name.
src/Propellor/Property.hs view
@@ -16,7 +16,6 @@ 	, check 	, fallback 	, revert-	, applyToList 	-- * Property descriptions 	, describe 	, (==>)@@ -54,7 +53,6 @@ import qualified Data.Hash.MD5 as MD5 import Data.List import Control.Applicative-import Data.Foldable hiding (and, elem) import Prelude  import Propellor.Types@@ -120,13 +118,15 @@         -> CombinedType x y onChange = combineWith combiner revertcombiner   where-	combiner p hook = do+	combiner (Just p) (Just hook) = Just $ do 		r <- p 		case r of 			MadeChange -> do 				r' <- hook 				return $ r <> r' 			_ -> return r+	combiner (Just p) Nothing = Just p+	combiner Nothing _ = Nothing 	revertcombiner = (<>)  -- | Same as `onChange` except that if property y fails, a flag file@@ -144,24 +144,30 @@         -> CombinedType x y onChangeFlagOnFail flagfile = combineWith combiner revertcombiner   where-	combiner s1 s2 = do+	combiner (Just s1) s2 = Just $ do 		r1 <- s1 		case r1 of 			MadeChange -> flagFailed s2 			_ -> ifM (liftIO $ doesFileExist flagfile)-				(flagFailed s2+				( flagFailed s2 				, return r1 				)+	combiner Nothing _ = Nothing+ 	revertcombiner = (<>)-	flagFailed s = do++	flagFailed (Just s) = do 		r <- s 		liftIO $ case r of 			FailedChange -> createFlagFile 			_ -> removeFlagFile 		return r+	flagFailed Nothing = return NoChange+ 	createFlagFile = unlessM (doesFileExist flagfile) $ do 		createDirectoryIfMissing True (takeDirectory flagfile) 		writeFile flagfile ""+	 	removeFlagFile = whenM (doesFileExist flagfile) $ removeFile flagfile  -- | Changes the description of a property.@@ -178,11 +184,13 @@ fallback :: (Combines p1 p2) => p1 -> p2 -> CombinedType p1 p2 fallback = combineWith combiner revertcombiner   where-	combiner a1 a2 = do+	combiner (Just a1) (Just a2) = Just $ do 		r <- a1 		if r == FailedChange 			then a2 			else return r+	combiner (Just a1) Nothing = Just a1+	combiner Nothing _ = Nothing 	revertcombiner = (<>)  -- | Indicates that a Property may change a particular file. When the file@@ -292,9 +300,9 @@ 	-- are added as children, so their info will propigate. 	c = withOS (getDesc a) $ \_ o -> 		if matching o a-			then getSatisfy a+			then maybe (pure NoChange) id (getSatisfy a) 			else if matching o b-				then getSatisfy b+				then maybe (pure NoChange) id (getSatisfy b) 				else unsupportedOS' 	matching Nothing _ = False 	matching (Just o) p =@@ -343,14 +351,6 @@ revert :: RevertableProperty setup undo -> RevertableProperty undo setup revert (RevertableProperty p1 p2) = RevertableProperty p2 p1 --- | Apply a property to each element of a list.-applyToList-	:: (Foldable t, Functor t, Combines p p, p ~ CombinedType p p)-	=> (b -> p)-	-> t b-	-> p-prop `applyToList` xs = Data.Foldable.foldr1 before $ prop <$> xs- makeChange :: IO () -> Propellor Result makeChange a = liftIO a >> return MadeChange @@ -358,7 +358,7 @@ noChange = return NoChange  doNothing :: SingI t => Property (MetaTypes t)-doNothing = property "noop property" noChange+doNothing = mempty  -- | Registers an action that should be run at the very end, after -- propellor has checks all the properties of a host.
src/Propellor/Property/Apache.hs view
@@ -64,6 +64,24 @@ 			`onChange` reloaded 	isenabled = boolSystem "a2query" [Param "-q", Param "-m", Param modname] +-- | Control whether an apache configuration file is enabled. +--+-- The String is the base name of the configuration, eg "charset" or "gitweb".+confEnabled :: String -> RevertableProperty DebianLike DebianLike+confEnabled confname = enable <!> disable+  where+	enable = check (not <$> isenabled)+		(cmdProperty "a2enconf" ["--quiet", confname])+			`describe` ("apache configuration enabled " ++ confname)+			`requires` installed+			`onChange` reloaded+	disable = check isenabled+		(cmdProperty "a2disconf" ["--quiet", confname])+			`describe` ("apache configuration disabled " ++ confname)+			`requires` installed+			`onChange` reloaded+	isenabled = boolSystem "a2query" [Param "-q", Param "-c", Param confname]+ -- | Make apache listen on the specified ports. -- -- Note that ports are also specified inside a site's config file,
src/Propellor/Property/Apt.hs view
@@ -265,7 +265,7 @@ 	:: [AptPackagePref] 	-> [(DebianSuite, PinPriority)] 	-> RevertableProperty Debian Debian-pinnedTo ps pins = (\p -> pinnedTo' p pins) `applyToList` ps+pinnedTo ps pins = mconcat (map (\p -> pinnedTo' p pins) ps) 	`describe` unwords (("pinned to " ++ showSuites):ps)   where 	showSuites = intercalate "," $ showSuite . fst <$> pins
src/Propellor/Property/Chroot.hs view
@@ -4,6 +4,7 @@ 	debootstrapped, 	bootstrapped, 	provisioned,+	hostChroot, 	Chroot(..), 	ChrootBootstrapper(..), 	Debootstrapped(..),@@ -40,18 +41,18 @@ -- | Specification of a chroot. Normally you'll use `debootstrapped` or -- `bootstrapped` to construct a Chroot value. data Chroot where-	Chroot :: ChrootBootstrapper b => FilePath -> b -> Host -> Chroot+	Chroot :: ChrootBootstrapper b => FilePath -> b -> InfoPropagator -> Host -> Chroot  instance IsContainer Chroot where-	containerProperties (Chroot _ _ h) = containerProperties h-	containerInfo (Chroot _ _ h) = containerInfo h-	setContainerProperties (Chroot loc b h) ps = Chroot loc b (setContainerProperties h ps)+	containerProperties (Chroot _ _ _ h) = containerProperties h+	containerInfo (Chroot _ _ _ h) = containerInfo h+	setContainerProperties (Chroot loc b p h) ps = Chroot loc b p (setContainerProperties h ps)  chrootSystem :: Chroot -> Maybe System chrootSystem = fromInfoVal . fromInfo . containerInfo  instance Show Chroot where-	show c@(Chroot loc _ _) = "Chroot " ++ loc ++ " " ++ show (chrootSystem c)+	show c@(Chroot loc _ _ _) = "Chroot " ++ loc ++ " " ++ show (chrootSystem c)  -- | Class of things that can do initial bootstrapping of an operating -- System in a chroot.@@ -115,7 +116,9 @@ -- | Defines a Chroot at the given location, bootstrapped with the -- specified ChrootBootstrapper. bootstrapped :: ChrootBootstrapper b => b -> FilePath -> Props metatypes -> Chroot-bootstrapped bootstrapper location ps = Chroot location bootstrapper (host location ps)+bootstrapped bootstrapper location ps = c+  where+	c = Chroot location bootstrapper (propagateChrootInfo c) (host location ps)  -- | Ensures that the chroot exists and is provisioned according to its -- properties.@@ -124,15 +127,14 @@ -- is first unmounted. Note that it does not ensure that any processes -- that might be running inside the chroot are stopped. provisioned :: Chroot -> RevertableProperty (HasInfo + Linux) Linux-provisioned c = provisioned' (propagateChrootInfo c) c False+provisioned c = provisioned' c False  provisioned'-	:: (Property Linux -> Property (HasInfo + Linux))-	-> Chroot+	:: Chroot 	-> Bool 	-> RevertableProperty (HasInfo + Linux) Linux-provisioned' propigator c@(Chroot loc bootstrapper _) systemdonly =-	(propigator $ setup `describe` chrootDesc c "exists")+provisioned' c@(Chroot loc bootstrapper infopropigator _) systemdonly =+	(infopropigator normalContainerInfo $ setup `describe` chrootDesc c "exists") 		<!> 	(teardown `describe` chrootDesc c "removed")   where@@ -151,17 +153,20 @@ 		property ("removed " ++ loc) $ 			makeChange (removeChroot loc) -propagateChrootInfo :: Chroot -> Property Linux -> Property (HasInfo + Linux)-propagateChrootInfo c@(Chroot location _ _) p = propagateContainer location c $-	p `setInfoProperty` chrootInfo c+type InfoPropagator = (PropagateInfo -> Bool) -> Property Linux -> Property (HasInfo + Linux) +propagateChrootInfo :: Chroot -> InfoPropagator+propagateChrootInfo c@(Chroot location _ _ _) pinfo p =+	propagateContainer location c pinfo $+		p `setInfoProperty` chrootInfo c+ chrootInfo :: Chroot -> Info-chrootInfo (Chroot loc _ h) = mempty `addInfo`+chrootInfo (Chroot loc _ _ h) = mempty `addInfo` 	mempty { _chroots = M.singleton loc h }  -- | Propellor is run inside the chroot to provision it. propellChroot :: Chroot -> ([String] -> IO (CreateProcess, IO ())) -> Bool -> Property UnixLike-propellChroot c@(Chroot loc _ _) mkproc systemdonly = property (chrootDesc c "provisioned") $ do+propellChroot c@(Chroot loc _ _ _) mkproc systemdonly = property (chrootDesc c "provisioned") $ do 	let d = localdir </> shimdir c 	let me = localdir </> "propellor" 	shim <- liftIO $ ifM (doesDirectoryExist d)@@ -200,7 +205,7 @@ 		return r  toChain :: HostName -> Chroot -> Bool -> IO CmdLine-toChain parenthost (Chroot loc _ _) systemdonly = do+toChain parenthost (Chroot loc _ _ _) systemdonly = do 	onconsole <- isConsole <$> getMessageHandle 	return $ ChrootChain parenthost loc systemdonly onconsole @@ -225,7 +230,7 @@ chain _ _ = errorMessage "bad chain command"  inChrootProcess :: Bool -> Chroot -> [String] -> IO (CreateProcess, IO ())-inChrootProcess keepprocmounted (Chroot loc _ _) cmd = do+inChrootProcess keepprocmounted (Chroot loc _ _ _) cmd = do 	mountproc 	return (proc "chroot" (loc:cmd), cleanup)   where@@ -245,13 +250,13 @@ provisioningLock containerloc = "chroot" </> mungeloc containerloc ++ ".lock"  shimdir :: Chroot -> FilePath-shimdir (Chroot loc _ _) = "chroot" </> mungeloc loc ++ ".shim"+shimdir (Chroot loc _ _ _) = "chroot" </> mungeloc loc ++ ".shim"  mungeloc :: FilePath -> String mungeloc = replace "/" "_"  chrootDesc :: Chroot -> String -> String-chrootDesc (Chroot loc _ _) desc = "chroot " ++ loc ++ " " ++ desc+chrootDesc (Chroot loc _ _ _) desc = "chroot " ++ loc ++ " " ++ desc  -- | Adding this property to a chroot prevents daemons and other services -- from being started, which is often something you want to prevent when@@ -287,3 +292,22 @@  newtype InChroot = InChroot Bool 	deriving (Typeable, Show)++-- | Generates a Chroot that has all the properties of a Host.+-- +-- Note that it's possible to create loops using this, where a host+-- contains a Chroot containing itself etc. Such loops will be detected at+-- runtime.+hostChroot :: ChrootBootstrapper bootstrapper => Host -> bootstrapper -> FilePath -> Chroot+hostChroot h bootstrapper d = chroot+  where+	chroot = Chroot d bootstrapper pinfo h+	pinfo = propagateHostChrootInfo h chroot++-- This is different than propagateChrootInfo in that Info using+-- HostContext is not made to use the name of the chroot as its context,+-- but instead uses the hostname of the Host.+propagateHostChrootInfo :: Host -> Chroot -> InfoPropagator+propagateHostChrootInfo h c pinfo p =+	propagateContainer (hostName h) c pinfo $+		p `setInfoProperty` chrootInfo c
src/Propellor/Property/Concurrent.hs view
@@ -64,10 +64,13 @@ 	-- Increase the number of capabilities right up to the number of 	-- processors, so that A `concurrently` B `concurrently` C 	-- runs all 3 properties on different processors when possible.-	go a1 a2 = do+	go (Just a1) (Just a2) = Just $ do 		n <- liftIO getNumProcessors 		withCapabilities n $ 			concurrentSatisfy a1 a2+	go (Just a1) Nothing = Just a1+	go Nothing (Just a2) = Just a2+	go Nothing Nothing = Nothing  -- | Ensures all the properties in the list, with a specified amount of -- concurrency.@@ -101,9 +104,9 @@ 			Nothing -> return r 			Just p -> do 				hn <- asks hostName-				r' <- actionMessageOn hn-					(getDesc p)-					(getSatisfy p)+				r' <- case getSatisfy p of+					Nothing -> return NoChange+					Just a -> actionMessageOn hn (getDesc p) a 				worker q (r <> r')  -- | Run an action with the number of capabiities increased as necessary to
src/Propellor/Property/Conductor.hs view
@@ -323,15 +323,15 @@ 	show (NotConductorFor l) = "NotConductorFor " ++ show (map hostName l)  instance IsInfo ConductorFor where-	propagateInfo _ = False+	propagateInfo _ = PropagateInfo False instance IsInfo NotConductorFor where-	propagateInfo _ = False+	propagateInfo _ = PropagateInfo False  -- Added to Info when a host has been orchestrated. newtype Orchestrated = Orchestrated Any 	deriving (Typeable, Monoid, Show) instance IsInfo Orchestrated where-	propagateInfo _ = False+	propagateInfo _ = PropagateInfo False  isOrchestrated :: Orchestrated -> Bool isOrchestrated (Orchestrated v) = getAny v
src/Propellor/Property/DiskImage.hs view
@@ -50,29 +50,7 @@ -- -- Then, the disk image is set up, and the chroot is copied into the -- appropriate partition(s) of it.------ Example use:------ > import Propellor.Property.DiskImage------ > let chroot d = Chroot.debootstrapped mempty d--- >	& osDebian Unstable X86_64--- >	& Apt.installed ["linux-image-amd64"]--- >	& User.hasPassword (User "root")--- >	& User.accountFor (User "demo")--- > 	& User.hasPassword (User "demo")--- >	& User.hasDesktopGroups (User "demo")--- > 	& ...--- > in imageBuilt "/srv/images/foo.img" chroot--- >	MSDOS (grubBooted PC)--- >	[ partition EXT2 `mountedAt` "/boot"--- >		`setFlag` BootFlag--- >	, partition EXT4 `mountedAt` "/"--- >		`addFreeSpace` MegaBytes 100--- >		`mountOpt` errorReadonly--- >	, swapPartition (MegaBytes 256)--- >	]---+--  -- Note that the disk image file is reused if it already exists, -- to avoid expensive IO to generate a new one. And, it's updated in-place, -- so its contents are undefined during the build process.@@ -81,6 +59,52 @@ -- chroot while the disk image is being built, which should prevent any -- daemons that are included from being started on the system that is -- building the disk image.+--+-- Example use:+--+-- > import Propellor.Property.DiskImage+-- > import Propellor.Property.Chroot+-- > +-- > foo = host "foo.example.com" $ props+-- > 	& imageBuilt "/srv/diskimages/disk.img" mychroot+-- >		MSDOS (grubBooted PC)+-- >		[ partition EXT2 `mountedAt` "/boot"+-- >			`setFlag` BootFlag+-- >		, partition EXT4 `mountedAt` "/"+-- >			`addFreeSpace` MegaBytes 100+-- >			`mountOpt` errorReadonly+-- >		, swapPartition (MegaBytes 256)+-- >		]+-- >  where+-- >	mychroot d = debootstrapped mempty d $ props+-- >		& osDebian Unstable X86_64+-- >		& Apt.installed ["linux-image-amd64"]+-- >		& User.hasPassword (User "root")+-- >		& User.accountFor (User "demo")+-- > 		& User.hasPassword (User "demo")+-- >		& User.hasDesktopGroups (User "demo")+-- > 		& ...+--+-- This can also be used with `Chroot.hostChroot` to build a disk image+-- that has all the properties of a Host. For example:+--+-- > foo :: Host+-- > foo = host "foo.example.com" $ props+-- >	& imageBuilt "/srv/diskimages/bar-disk.img"+-- >		(hostChroot bar (Debootstrapped mempty))+-- >		MSDOS (grubBooted PC)+-- >		[ partition EXT2 `mountedAt` "/boot"+-- >			`setFlag` BootFlag+-- >		, partition EXT4 `mountedAt` "/"+-- >			`addFreeSpace` MegaBytes 5000+-- >		, swapPartition (MegaBytes 256)+-- >		]+-- >+-- > bar :: Host+-- > bar = host "bar.example.com" $ props+-- >	& osDebian Unstable X86_64+-- >	& Apt.installed ["linux-image-amd64"]+-- >	& hasPassword (User "root") imageBuilt :: DiskImage -> (FilePath -> Chroot) -> TableType -> Finalization -> [PartSpec] -> RevertableProperty (HasInfo + DebianLike) Linux imageBuilt = imageBuilt' False @@ -106,7 +130,7 @@ 		| otherwise = doNothing 	chrootdir = img ++ ".chroot" 	chroot =-		let c = mkchroot chrootdir+		let c = propprivdataonly $ mkchroot chrootdir 		in setContainerProps c $ containerProps c 			-- Before ensuring any other properties of the chroot, 			-- avoid starting services. Reverted by imageFinalized.@@ -114,6 +138,9 @@ 			-- First stage finalization. 			& fst final 			& cachesCleaned+	-- Only propagate privdata Info from this chroot, nothing else.+	propprivdataonly (Chroot.Chroot d b ip h) =+		Chroot.Chroot d b (const $ ip onlyPrivData) h  -- | This property is automatically added to the chroot when building a -- disk image. It cleans any caches of information that can be omitted;
src/Propellor/Property/Docker.hs view
@@ -184,8 +184,9 @@ 	image = getImageName ctr  propagateContainerInfo :: Container -> Property (HasInfo + Linux) -> Property (HasInfo + Linux)-propagateContainerInfo ctr@(Container _ h) p = propagateContainer cn ctr $-	p `addInfoProperty` dockerinfo+propagateContainerInfo ctr@(Container _ h) p = +	propagateContainer cn ctr normalContainerInfo $+		p `addInfoProperty` dockerinfo   where 	dockerinfo = dockerInfo $ 		mempty { _dockerContainers = M.singleton cn h }
src/Propellor/Property/Firejail.hs view
@@ -22,7 +22,7 @@ -- -- See "DESKTOP INTEGRATION" in firejail(1). jailed :: [String] -> Property DebianLike-jailed ps = (jailed' `applyToList` ps)+jailed ps = mconcat (map jailed' ps) 	`requires` installed 	`describe` unwords ("firejail jailed":ps) 
src/Propellor/Property/FreeBSD/Pkg.hs view
@@ -39,7 +39,7 @@ newtype PkgUpdate = PkgUpdate String 	deriving (Typeable, Monoid, Show) instance IsInfo PkgUpdate where-	propagateInfo _ = False+	propagateInfo _ = PropagateInfo False  pkgUpdated :: PkgUpdate -> Bool pkgUpdated (PkgUpdate _) = True@@ -55,8 +55,9 @@  newtype PkgUpgrade = PkgUpgrade String 	deriving (Typeable, Monoid, Show)+ instance IsInfo PkgUpgrade where-	propagateInfo _ = False+	propagateInfo _ = PropagateInfo False  pkgUpgraded :: PkgUpgrade -> Bool pkgUpgraded (PkgUpgrade _) = True
src/Propellor/Property/FreeBSD/Poudriere.hs view
@@ -21,7 +21,7 @@ 	deriving (Typeable, Monoid, Show)  instance IsInfo PoudriereConfigured where-	propagateInfo _ = False+	propagateInfo _ = PropagateInfo False  poudriereConfigured :: PoudriereConfigured -> Bool poudriereConfigured (PoudriereConfigured _) = True
src/Propellor/Property/List.hs view
@@ -53,7 +53,7 @@ combineSatisfy :: [ChildProperty] -> Result -> Propellor Result combineSatisfy [] rs = return rs combineSatisfy (p:ps) rs = do-	r <- catchPropellor $ getSatisfy p+	r <- maybe (pure NoChange) catchPropellor (getSatisfy p) 	case r of 		FailedChange -> return FailedChange 		_ -> combineSatisfy ps (r <> rs)
src/Propellor/Property/SiteSpecific/JoeySites.hs view
@@ -228,23 +228,29 @@ 		`requires` Ssh.knownHost hosts "usw-s002.rsync.net" (User "root") 		`requires` Ssh.authorizedKeys (User "family") (Context "git.kitenet.net") 		`requires` User.accountFor (User "family")-	& Apt.installed ["git", "rsync", "gitweb"]+	& Apt.installed ["git", "rsync", "cgit"] 	& Apt.installed ["git-annex"] 	& Apt.installed ["kgb-client"] 	& File.hasPrivContentExposed "/etc/kgb-bot/kgb-client.conf" anyContext 		`requires` File.dirExists "/etc/kgb-bot/" 	& Git.daemonRunning "/srv/git"-	& "/etc/gitweb.conf" `File.containsLines`-		[ "$projectroot = '/srv/git';"-		, "@git_base_url_list = ('git://git.kitenet.net', 'http://git.kitenet.net/git', 'https://git.kitenet.net/git', 'ssh://git.kitenet.net/srv/git');"-		, "# disable snapshot download; overloads server"-		, "$feature{'snapshot'}{'default'} = [];"+	& "/etc/cgitrc" `File.hasContent`+		[ "clone-url=https://git.joeyh.name/git/$CGIT_REPO_URL git://git.joeyh.name/$CGIT_REPO_URL"+		, "css=/cgit-css/cgit.css"+		, "logo=/cgit-css/cgit.png"+		, "enable-http-clone=1"+		, "root-title=Joey's git repositories"+		, "root-desc="+		, "enable-index-owner=0"+		, "snapshots=tar.gz"+		, "enable-git-config=1"+		, "scan-path=/srv/git" 		]-		`describe` "gitweb configured"-	-- Repos push on to github.-	& Ssh.knownHost hosts "github.com" (User "joey")-	-- I keep the website used for gitweb checked into git..+		`describe` "cgit configured"+	-- I keep the website used for git.kitenet.net/git.joeyh.name checked into git.. 	& Git.cloned (User "root") "/srv/git/joey/git.kitenet.net.git" "/srv/web/git.kitenet.net" Nothing+	-- Don't need global apache configuration for cgit.+	! Apache.confEnabled "cgit" 	& website "git.kitenet.net" 	& website "git.joeyh.name" 	& Apache.modEnabled "cgi"
src/Propellor/Property/Ssh.hs view
@@ -227,7 +227,7 @@ 	deriving (Eq, Ord, Typeable, Show)  instance IsInfo HostKeyInfo where-	propagateInfo _ = False+	propagateInfo _ = PropagateInfo False  instance Monoid HostKeyInfo where 	mempty = HostKeyInfo M.empty@@ -248,7 +248,7 @@ 	deriving (Eq, Ord, Typeable, Show)  instance IsInfo UserKeyInfo where-	propagateInfo _ = False+	propagateInfo _ = PropagateInfo False  instance Monoid UserKeyInfo where 	mempty = UserKeyInfo M.empty
src/Propellor/Property/Systemd.hs view
@@ -259,7 +259,7 @@ -- Reverting this property stops the container, removes the systemd unit, -- and deletes the chroot and all its contents. nspawned :: Container -> RevertableProperty (HasInfo + Linux) Linux-nspawned c@(Container name (Chroot.Chroot loc builder _) h) =+nspawned c@(Container name (Chroot.Chroot loc builder _ _) h) = 	p `describe` ("nspawned " ++ name)   where 	p :: RevertableProperty (HasInfo + Linux) Linux@@ -271,7 +271,7 @@ 	-- Chroot provisioning is run in systemd-only mode, 	-- which sets up the chroot and ensures systemd and dbus are 	-- installed, but does not handle the other properties.-	chrootprovisioned = Chroot.provisioned' (Chroot.propagateChrootInfo chroot) chroot True+	chrootprovisioned = Chroot.provisioned' chroot True  	-- Use nsenter to enter container and and run propellor to 	-- finish provisioning.@@ -281,7 +281,7 @@ 			<!> 		doNothing -	chroot = Chroot.Chroot loc builder h+	chroot = Chroot.Chroot loc builder (Chroot.propagateChrootInfo chroot) h  -- | Sets up the service file for the container, and then starts -- it running.
src/Propellor/Types.hs view
@@ -12,6 +12,7 @@ 	  Host(..) 	, Property(..) 	, property+	, property'' 	, Desc 	, RevertableProperty(..) 	, (<!>)@@ -56,7 +57,6 @@ -- | The core data type of Propellor, this represents a property -- that the system should have, with a descrition, and an action to ensure -- it has the property.--- that have the property. -- -- There are different types of properties that target different OS's, -- and so have different metatypes. @@ -67,7 +67,7 @@ -- -- There are many associated type families, which are mostly used -- internally, so you needn't worry about them.-data Property metatypes = Property metatypes Desc (Propellor Result) Info [ChildProperty]+data Property metatypes = Property metatypes Desc (Maybe (Propellor Result)) Info [ChildProperty]  instance Show (Property metatypes) where 	show p = "property " ++ show (getDesc p)@@ -90,11 +90,18 @@ 	=> Desc 	-> Propellor Result 	-> Property (MetaTypes metatypes)-property d a = Property sing d a mempty mempty+property d a = Property sing d (Just a) mempty mempty +property''+	:: SingI metatypes+	=> Desc+	-> Maybe (Propellor Result)+	-> Property (MetaTypes metatypes)+property'' d a = Property sing d a mempty mempty+ -- | Changes the action that is performed to satisfy a property. adjustPropertySatisfy :: Property metatypes -> (Propellor Result -> Propellor Result) -> Property metatypes-adjustPropertySatisfy (Property t d s i c) f = Property t d (f s) i c+adjustPropertySatisfy (Property t d s i c) f = Property t d (f <$> s) i c  -- | A property that can be reverted. The first Property is run -- normally and the second is run when it's reverted.@@ -148,7 +155,7 @@ type instance CombinedType (RevertableProperty (MetaTypes x) (MetaTypes x')) (Property (MetaTypes y)) = Property (MetaTypes (Combine x y)) type instance CombinedType (Property (MetaTypes x)) (RevertableProperty (MetaTypes y) (MetaTypes y')) = Property (MetaTypes (Combine x y)) -type ResultCombiner = Propellor Result -> Propellor Result -> Propellor Result+type ResultCombiner = Maybe (Propellor Result) -> Maybe (Propellor Result) -> Maybe (Propellor Result)  class Combines x y where 	-- | Combines together two properties, yielding a property that@@ -198,3 +205,35 @@  instance TightenTargets Property where 	tightenTargets (Property _ d a i c) = Property sing d a i c++-- | Any type of Property is a monoid. When properties x and y are+-- appended together, the resulting property has a description like+-- "x and y". Note that when x fails to be ensured, it will not+-- try to ensure y.+instance SingI metatypes => Monoid (Property (MetaTypes metatypes))+  where+	mempty = Property sing "noop property" Nothing mempty mempty+	mappend (Property _ d1 a1 i1 c1) (Property _ d2 a2 i2 c2) =+	  	Property sing d (a1 <> a2) (i1 <> i2) (c1 <> c2)+	  where+		-- Avoid including "noop property" in description+		-- when using eg mconcat.+		d = case (a1, a2) of+			(Just _, Just _) -> d1 <> " and " <> d2+			(Just _, Nothing) -> d1+			(Nothing, Just _) -> d2+			(Nothing, Nothing) -> d1++-- | Any type of RevertableProperty is a monoid. When revertable +-- properties x and y are appended together, the resulting revertable+-- property has a description like "x and y".+-- Note that when x fails to be ensured, it will not try to ensure y.+instance+	( Monoid (Property setupmetatypes)+	, Monoid (Property undometatypes)+	)+	=> Monoid (RevertableProperty setupmetatypes undometatypes)+  where+	mempty = RevertableProperty mempty mempty+	mappend (RevertableProperty s1 u1) (RevertableProperty s2 u2) =+		RevertableProperty (s1 <> s2) (u2 <> u1)
src/Propellor/Types/Chroot.hs view
@@ -16,7 +16,7 @@ 	deriving (Show, Typeable)  instance IsInfo ChrootInfo where-	propagateInfo _ = False+	propagateInfo _ = PropagateInfo False  instance Monoid ChrootInfo where 	mempty = ChrootInfo mempty mempty
src/Propellor/Types/Core.hs view
@@ -48,9 +48,10 @@ instance LiftPropellor IO where 	liftPropellor = liftIO +-- | When two actions are appended together, the second action+-- is only run if the first action does not fail. instance Monoid (Propellor Result) where 	mempty = return NoChange-	-- | The second action is only run if the first action does not fail. 	mappend x y = do 		rx <- x 		case rx of@@ -71,7 +72,7 @@  -- | Since there are many different types of Properties, they cannot be put -- into a list. The simplified ChildProperty can be put into a list.-data ChildProperty = ChildProperty Desc (Propellor Result) Info [ChildProperty]+data ChildProperty = ChildProperty Desc (Maybe (Propellor Result)) Info [ChildProperty]    instance Show ChildProperty where 	show p = "property " ++ show (getDesc p)@@ -92,7 +93,7 @@ 	-- | Gets the action that can be run to satisfy a Property. 	-- You should never run this action directly. Use 	-- 'Propellor.EnsureProperty.ensureProperty` instead.-	getSatisfy :: p -> Propellor Result+	getSatisfy :: p -> Maybe (Propellor Result)  instance IsProp ChildProperty where 	setDesc (ChildProperty _ a i c) d = ChildProperty d a i c
src/Propellor/Types/Dns.hs view
@@ -28,7 +28,7 @@ 	deriving (Show, Eq, Ord, Monoid, Typeable)  instance IsInfo AliasesInfo where-	propagateInfo _ = False+	propagateInfo _ = PropagateInfo False  toAliasesInfo :: [HostName] -> AliasesInfo toAliasesInfo l = AliasesInfo (S.fromList l)@@ -45,7 +45,7 @@ -- | DNS Info is propagated, so that eg, aliases of a container -- are reflected in the dns for the host where it runs. instance IsInfo DnsInfo where-	propagateInfo _ = True+	propagateInfo _ = PropagateInfo True  -- | Represents a bind 9 named.conf file. data NamedConf = NamedConf@@ -157,7 +157,7 @@ 	deriving (Eq, Ord, Show, Typeable)  instance IsInfo NamedConfMap where-	propagateInfo _ = False+	propagateInfo _ = PropagateInfo False  -- | Adding a Master NamedConf stanza for a particulr domain always -- overrides an existing Secondary stanza for that domain, while a
src/Propellor/Types/Docker.hs view
@@ -16,7 +16,7 @@ 	deriving (Show, Typeable)  instance IsInfo DockerInfo where-	propagateInfo _ = False+	propagateInfo _ = PropagateInfo False  instance Monoid DockerInfo where 	mempty = DockerInfo mempty mempty
src/Propellor/Types/Info.hs view
@@ -1,13 +1,14 @@ {-# LANGUAGE GADTs, DeriveDataTypeable, GeneralizedNewtypeDeriving #-}  module Propellor.Types.Info (-	Info,+	Info(..),+	InfoEntry(..), 	IsInfo(..),+	PropagateInfo(..), 	addInfo, 	toInfo, 	fromInfo, 	mapInfo,-	propagatableInfo, 	InfoVal(..), 	fromInfoVal, 	Typeable,@@ -44,8 +45,14 @@ class (Typeable v, Monoid v, Show v) => IsInfo v where 	-- | Should info of this type be propagated out of a 	-- container to its Host?-	propagateInfo :: v -> Bool+	propagateInfo :: v -> PropagateInfo +data PropagateInfo+	= PropagateInfo Bool+	| PropagatePrivData+	-- ^ Info about PrivData generally will be propigated even in cases+	-- where other Info is not, so it treated specially.+ -- | Any value in the `IsInfo` type class can be added to an Info. addInfo :: IsInfo v => Info -> v -> Info addInfo (Info l) v = Info (InfoEntry v:l)@@ -68,11 +75,6 @@ 		Nothing -> i 		Just v -> InfoEntry (f v) --- | Filters out parts of the Info that should not propagate out of a--- container.-propagatableInfo :: Info -> Info-propagatableInfo (Info l) = Info (filter (\(InfoEntry a) -> propagateInfo a) l)- -- | Use this to put a value in Info that is not a monoid. -- The last value set will be used. This info does not propagate -- out of a container.@@ -85,7 +87,7 @@ 	mappend v NoInfoVal = v  instance (Typeable v, Show v) => IsInfo (InfoVal v) where-	propagateInfo _ = False+	propagateInfo _ = PropagateInfo False  fromInfoVal :: InfoVal v -> Maybe v fromInfoVal NoInfoVal = Nothing