summaryrefslogtreecommitdiff
path: root/src/Propellor/Property/Spin.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Propellor/Property/Spin.hs')
-rw-r--r--src/Propellor/Property/Spin.hs86
1 files changed, 65 insertions, 21 deletions
diff --git a/src/Propellor/Property/Spin.hs b/src/Propellor/Property/Spin.hs
index 599fefd1..a08352d3 100644
--- a/src/Propellor/Property/Spin.hs
+++ b/src/Propellor/Property/Spin.hs
@@ -1,27 +1,35 @@
{-# LANGUAGE FlexibleInstances #-}
-module Propellor.Property.Spin (Spinnable(..), controller) where
+module Propellor.Property.Spin (
+ Spinnable(..),
+ controllerFor,
+ controllerKeys,
+ controlledBy,
+) where
import Propellor.Base
import Propellor.Spin (spin)
import Propellor.Types.CmdLine (ControllerChain(..))
import Propellor.Types.Info
+import qualified Propellor.Property.Ssh as Ssh
-- | A class of things that can be spinned.
class Spinnable t where
toSpin :: t -> Property NoInfo
instance Spinnable Host where
- toSpin h = property (cdesc (hostName h)) $ do
- ControllerChain cc <- getControllerChain
- if hostName h `elem` cc
- then noChange -- avoid loop
- else do
- liftIO $ spin (hostName h) Nothing (ControllerChain cc) h
- -- Don't know if the spin made a change to the
- -- remote host or not, but in any case, the
- -- local host was not changed.
- noChange
+ toSpin h = go `requires` Ssh.knownHost [h] (hostName h) (User "root")
+ where
+ go = property (cdesc (hostName h)) $ do
+ ControllerChain cc <- getControllerChain
+ if hostName h `elem` cc
+ then noChange -- avoid loop
+ else do
+ liftIO $ spin (hostName h) Nothing (ControllerChain cc) h
+ -- Don't know if the spin made a change to the
+ -- remote host or not, but in any case, the
+ -- local host was not changed.
+ noChange
-- | Each Host in the list is spinned in turn. Does not stop on spin
-- failure; does propigate overall success/failure.
@@ -36,26 +44,47 @@ instance Spinnable [Host] where
-- propellor is run on the controller host, it will in turn run
-- propellor on the controlled Hosts.
--
--- For example, if you have some webservers and some dnsservers,
+-- The controller needs to be able to ssh to the hosts it controls,
+-- and run propellor, as root. The controller is automatically configured
+-- with `Propellor.Property.Ssh.knownHost` to know the host keys of the
+-- hosts that it will ssh to. It's up to you to use `controllerKey`
+-- and `controlledBy` to set up the ssh keys that will let the controller
+-- log into the hosts it controls.
+--
+-- For example, if you have some webservers and a dnsserver,
-- and want a master that runs propellor on all of them:
--
-- > import Propellor
-- > import qualified Propellor.Property.Spin as Spin
+-- > import qualified Propellor.Property.Ssh as Ssh
-- > import qualified Propellor.Property.Cron as Cron
-- >
-- > main = defaultMain hosts
-- >
--- > hosts = master : webservers ++ dnsservers
--- >
--- > webservers = ...
+-- > hosts =
+-- > [ master
+-- > , dnsserver
+-- > ] ++ webservers
-- >
--- > dnsservers = ...
+-- > dnsserver = host "dns.example.com"
+-- > & Ssh.hostKeys hostContext [(SshEcdsa, "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB3BJ2GqZiTR2LEoDXyYFgh/BduWefjdKXAsAtzS9zeI")]
+-- > & Spin.controlledBy master
+-- > & ...
-- >
+-- > webservers =
+-- > [ host "www1.example.com"
+-- > & Ssh.hostKeys hostContext [(SshEcdsa, "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICfFntnesZcYz2B2T41ay45igfckXRSh5uVffkuCQkLv")]
+-- > & Spin.controlledBy master
+-- > & ...
+-- > , ...
+-- > ]
+-- >
-- > master = host "master.example.com"
+-- > & Spin.controllerKeys [(SshEcdsa, "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFWD0Hau5FDLeNrDHKilNMKm9c68R3WD+NJOp2jPWvJV")]
+-- > -- Only update dnsserver once all webservers are successfully updated.
+-- > & Spin.controllerFor dnsserver
+-- > `requires` Spin.controllerFor webservers
-- > & Cron.runPropellor
--- > -- Only update dnsservers once all webservers are successfully updated.
--- > & Spin.controller dnsservers
--- > `requires` Spin.controller webservers
--
-- Multiple controllers can control the same hosts. However, when
-- propellor is already running on a host, a controller will fail
@@ -64,12 +93,27 @@ instance Spinnable [Host] where
--
-- Chains of controllers are supported; host A can control host B which
-- controls host C. Loops of controllers are automatically prevented.
-controller :: Spinnable h => h -> Property NoInfo
-controller = toSpin
+controllerFor :: Spinnable h => h -> Property NoInfo
+controllerFor h = toSpin h
+ `requires` Ssh.installed
+
+-- | Uses `Propellor.Property.Ssh.keysImported` to set up the ssh keys
+-- for a controller; so the corresponding private keys come from the privdata.
+controllerKeys :: [(SshKeyType, Ssh.PubKeyText)] -> Property HasInfo
+controllerKeys ks = Ssh.userKeys (User "root") hostContext ks
+ `requires` Ssh.installed
+
+-- | Use this property to let the specified controller Host ssh in
+-- and run propellor.
+controlledBy :: Host -> Property NoInfo
+controlledBy h = User "root" `Ssh.authorizedKeysFrom` (User "root", h)
+ `requires` Ssh.installed
cdesc :: String -> Desc
cdesc n = "controller for " ++ n
+-- | The current host is included on the chain, as well as any hosts that
+-- acted as controllers to get the current propellor process to run.
getControllerChain :: Propellor ControllerChain
getControllerChain = do
hn <- hostName <$> ask