diff options
| author | Joey Hess <joey@kitenet.net> | 2014-11-21 17:29:47 -0400 |
|---|---|---|
| committer | Joey Hess <joey@kitenet.net> | 2014-11-21 17:29:47 -0400 |
| commit | e60b261daea356a2fcab424a276a491fdd3f956c (patch) | |
| tree | 1acb5a387f77b9749023fc5de188268a39636a02 /src/Propellor/Property/Systemd.hs | |
| parent | 7ecb632b7ce1d97559646c3af71bb54db82c99e3 (diff) | |
| parent | 04ea987075b869ea70cf55a193af7f5604ff0561 (diff) | |
Merge branch 'joeyconfig'
Diffstat (limited to 'src/Propellor/Property/Systemd.hs')
| -rw-r--r-- | src/Propellor/Property/Systemd.hs | 152 |
1 files changed, 111 insertions, 41 deletions
diff --git a/src/Propellor/Property/Systemd.hs b/src/Propellor/Property/Systemd.hs index be08a847..b50194fa 100644 --- a/src/Propellor/Property/Systemd.hs +++ b/src/Propellor/Property/Systemd.hs @@ -1,6 +1,11 @@ module Propellor.Property.Systemd ( - installed, + module Propellor.Property.Systemd.Core, + started, + stopped, + enabled, + disabled, persistentJournal, + Container, container, nspawned, ) where @@ -8,44 +13,69 @@ module Propellor.Property.Systemd ( import Propellor import qualified Propellor.Property.Chroot as Chroot import qualified Propellor.Property.Apt as Apt +import qualified Propellor.Property.File as File +import Propellor.Property.Systemd.Core import Utility.SafeCommand +import Utility.FileMode import Data.List.Utils -type MachineName = String +type ServiceName = String -type NspawnParam = CommandParam +type MachineName = String -data Container = Container MachineName System [CommandParam] Host +data Container = Container MachineName Chroot.Chroot Host instance Hostlike Container where - (Container n s ps h) & p = Container n s ps (h & p) - (Container n s ps h) &^ p = Container n s ps (h &^ p) - getHost (Container _ _ _ h) = h + (Container n c h) & p = Container n c (h & p) + (Container n c h) &^ p = Container n c (h &^ p) + getHost (Container _ _ h) = h + +-- | Starts a systemd service. +started :: ServiceName -> Property +started n = trivial $ cmdProperty "systemctl" ["start", n] + `describe` ("service " ++ n ++ " started") + +-- | Stops a systemd service. +stopped :: ServiceName -> Property +stopped n = trivial $ cmdProperty "systemctl" ["stop", n] + `describe` ("service " ++ n ++ " stopped") --- dbus is only a Recommends of systemd, but is needed for communication --- from the systemd inside a container to the one outside, so make sure it --- gets installed. -installed :: Property -installed = Apt.installed ["systemd", "dbus"] +-- | Enables a systemd service. +enabled :: ServiceName -> Property +enabled n = trivial $ cmdProperty "systemctl" ["enable", n] + `describe` ("service " ++ n ++ " enabled") --- | Sets up persistent storage of the journal. +-- | Disables a systemd service. +disabled :: ServiceName -> Property +disabled n = trivial $ cmdProperty "systemctl" ["disable", n] + `describe` ("service " ++ n ++ " disabled") + +-- | Enables persistent storage of the journal. persistentJournal :: Property persistentJournal = check (not <$> doesDirectoryExist dir) $ - combineProperties "persistent systetemd journal" + combineProperties "persistent systemd journal" [ cmdProperty "install" ["-d", "-g", "systemd-journal", dir] , cmdProperty "setfacl" ["-R", "-nm", "g:adm:rx,d:g:adm:rx", dir] + , started "systemd-journal-flush" ] `requires` Apt.installed ["acl"] where dir = "/var/log/journal" --- | Defines a container with a given machine name, containing the specified --- System. Properties can be added to configure the Container. +-- | Defines a container with a given machine name. +-- +-- Properties can be added to configure the Container. -- --- > container "webserver" (System (Debian Unstable) "amd64") [] -container :: MachineName -> System -> [NspawnParam] -> Container -container name system ps = Container name system ps (Host name [] mempty) +-- > container "webserver" (Chroot.debootstrapped (System (Debian Unstable) "amd64") mempty) +-- > & Apt.installedRunning "apache2" +-- > & ... +container :: MachineName -> (FilePath -> Chroot.Chroot) -> Container +container name mkchroot = Container name c h + & os system + where + c@(Chroot.Chroot _ system _ _) = mkchroot (containerDir name) + h = Host name [] mempty -- | Runs a container using systemd-nspawn. -- @@ -62,42 +92,82 @@ container name system ps = Container name system ps (Host name [] mempty) -- Reverting this property stops the container, removes the systemd unit, -- and deletes the chroot and all its contents. nspawned :: Container -> RevertableProperty -nspawned c@(Container name system _ h) = RevertableProperty setup teardown +nspawned c@(Container name (Chroot.Chroot loc system builderconf _) h) = + RevertableProperty setup teardown where - -- TODO after container is running, use nsenter to enter it - -- and run propellor to finish provisioning. - setup = toProp (nspawnService c) - `requires` toProp chrootprovisioned + setup = combineProperties ("nspawned " ++ name) $ + map toProp steps ++ [containerprovisioned] + teardown = combineProperties ("not nspawned " ++ name) $ + map (toProp . revert) (reverse steps) + steps = + [ enterScript c + , chrootprovisioned + , nspawnService c + ] - teardown = toProp (revert (chrootprovisioned)) - `requires` toProp (revert (nspawnService c)) + -- 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 provisions. + chrootprovisioned = Chroot.provisioned' + (Chroot.propigateChrootInfo chroot) chroot True - -- When provisioning the chroot, pass a version of the Host - -- that only has the Property of systemd being installed. - -- This is to avoid starting any daemons in the chroot, - -- which would not run in the container's namespace. - chrootprovisioned = Chroot.provisioned $ - Chroot.Chroot (containerDir name) system $ - h { hostProperties = [installed] } + -- Use nsenter to enter container and and run propellor to + -- finish provisioning. + containerprovisioned = Chroot.propellChroot chroot + (enterContainerProcess c) False + + chroot = Chroot.Chroot loc system builderconf h nspawnService :: Container -> RevertableProperty -nspawnService (Container name _ ps _) = RevertableProperty setup teardown +nspawnService (Container name _ _) = RevertableProperty setup teardown where service = nspawnServiceName name servicefile = "/etc/systemd/system/multi-user.target.wants" </> service setup = check (not <$> doesFileExist servicefile) $ - combineProperties ("container running " ++ service) - [ cmdProperty "systemctl" ["enable", service] - , cmdProperty "systemctl" ["start", service] + started service + `requires` enabled service + + teardown = check (doesFileExist servicefile) $ + disabled service + `requires` stopped service + +-- | Installs a "enter-machinename" script that root can use to run a +-- command inside the container. +-- +-- This uses nsenter to enter the container, by looking up the pid of the +-- container's init process and using its namespace. +enterScript :: Container -> RevertableProperty +enterScript c@(Container name _ _) = RevertableProperty setup teardown + where + setup = combineProperties ("generated " ++ enterScriptFile c) + [ scriptfile `File.hasContent` + [ "#!/bin/sh" + , "# Generated by propellor" + , "pid=\"$(machinectl show " ++ shellEscape name ++ " -p Leader | cut -d= -f2)\" || true" + , "if [ -n \"$pid\" ]; then" + , "\tnsenter -p -u -n -i -m -t \"$pid\" \"$@\"" + , "else" + , "\techo container not running >&2" + , "\texit 1" + , "fi" ] + , scriptfile `File.mode` combineModes (readModes ++ executeModes) + ] + teardown = File.notPresent scriptfile + scriptfile = enterScriptFile c - -- TODO adjust execStart line to reflect ps +enterScriptFile :: Container -> FilePath +enterScriptFile (Container name _ _ ) = "/usr/local/bin/enter-" ++ mungename name - teardown = undefined +enterContainerProcess :: Container -> [String] -> CreateProcess +enterContainerProcess = proc . enterScriptFile -nspawnServiceName :: MachineName -> String +nspawnServiceName :: MachineName -> ServiceName nspawnServiceName name = "systemd-nspawn@" ++ name ++ ".service" containerDir :: MachineName -> FilePath -containerDir name = "/var/lib/container" ++ replace "/" "_" name +containerDir name = "/var/lib/container" </> mungename name + +mungename :: MachineName -> String +mungename = replace "/" "_" |
