From 6a5a1bc76132128e4bd2312dfadc98e83b0baf40 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 21 Nov 2014 12:17:03 -0400 Subject: systemd container may be mostly done (untested) --- config-joey.hs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'config-joey.hs') diff --git a/config-joey.hs b/config-joey.hs index a11e1d8c..62c5af9f 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -25,6 +25,7 @@ import qualified Propellor.Property.Grub as Grub import qualified Propellor.Property.Obnam as Obnam import qualified Propellor.Property.Gpg as Gpg import qualified Propellor.Property.Chroot as Chroot +import qualified Propellor.Property.Systemd as Systemd import qualified Propellor.Property.HostingProvider.DigitalOcean as DigitalOcean import qualified Propellor.Property.HostingProvider.CloudAtCost as CloudAtCost import qualified Propellor.Property.HostingProvider.Linode as Linode @@ -80,7 +81,13 @@ clam = standardSystem "clam.kitenet.net" Unstable "amd64" ! Ssh.listenPort 80 ! Ssh.listenPort 443 - & Chroot.provisioned testChroot + ! Chroot.provisioned testChroot + & Systemd.persistentJournal + & Systemd.nspawned meow + +meow :: Systemd.Container +meow = Systemd.container "meow" (System (Debian Unstable) "amd64") [] + & Apt.serviceInstalledRunning ["fingerd"] testChroot :: Chroot.Chroot testChroot = Chroot.chroot "/tmp/chroot" (System (Debian Unstable) "amd64") -- cgit v1.3-2-g0d8e From 976afedea3fabc98ac64d72bbad3aacd7602f84d Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 21 Nov 2014 12:18:03 -0400 Subject: propellor spin --- config-joey.hs | 2 +- src/Propellor/Property/Systemd.hs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'config-joey.hs') diff --git a/config-joey.hs b/config-joey.hs index 62c5af9f..b2b324f7 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -87,7 +87,7 @@ clam = standardSystem "clam.kitenet.net" Unstable "amd64" meow :: Systemd.Container meow = Systemd.container "meow" (System (Debian Unstable) "amd64") [] - & Apt.serviceInstalledRunning ["fingerd"] + & Apt.serviceInstalledRunning "fingerd" testChroot :: Chroot.Chroot testChroot = Chroot.chroot "/tmp/chroot" (System (Debian Unstable) "amd64") diff --git a/src/Propellor/Property/Systemd.hs b/src/Propellor/Property/Systemd.hs index 63a150f6..88c03743 100644 --- a/src/Propellor/Property/Systemd.hs +++ b/src/Propellor/Property/Systemd.hs @@ -1,6 +1,7 @@ module Propellor.Property.Systemd ( installed, persistentJournal, + Container, container, nspawned, ) where -- cgit v1.3-2-g0d8e From cf3a8883ecec79ad8b44be956ae98db3bfa3f42f Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 21 Nov 2014 14:17:19 -0400 Subject: propellor spin --- config-joey.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'config-joey.hs') diff --git a/config-joey.hs b/config-joey.hs index b2b324f7..da7d8ea7 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -87,7 +87,7 @@ clam = standardSystem "clam.kitenet.net" Unstable "amd64" meow :: Systemd.Container meow = Systemd.container "meow" (System (Debian Unstable) "amd64") [] - & Apt.serviceInstalledRunning "fingerd" + & Apt.serviceInstalledRunning "uptimed" testChroot :: Chroot.Chroot testChroot = Chroot.chroot "/tmp/chroot" (System (Debian Unstable) "amd64") -- cgit v1.3-2-g0d8e From 36e89cd148cd266254f4c50c5396d05433ed9bb3 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 21 Nov 2014 14:31:13 -0400 Subject: os info propigation Also, lost the systemd-nspawn parameters; I'll do that some other way. --- config-joey.hs | 3 ++- src/Propellor/Property/Chroot.hs | 2 ++ src/Propellor/Property/Systemd.hs | 28 ++++++++++++++-------------- 3 files changed, 18 insertions(+), 15 deletions(-) (limited to 'config-joey.hs') diff --git a/config-joey.hs b/config-joey.hs index da7d8ea7..a12544df 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -86,8 +86,9 @@ clam = standardSystem "clam.kitenet.net" Unstable "amd64" & Systemd.nspawned meow meow :: Systemd.Container -meow = Systemd.container "meow" (System (Debian Unstable) "amd64") [] +meow = Systemd.container "meow" (System (Debian Unstable) "amd64") & Apt.serviceInstalledRunning "uptimed" + & alias "meow.kitenet.net" testChroot :: Chroot.Chroot testChroot = Chroot.chroot "/tmp/chroot" (System (Debian Unstable) "amd64") diff --git a/src/Propellor/Property/Chroot.hs b/src/Propellor/Property/Chroot.hs index 7fee3a59..2aad26f3 100644 --- a/src/Propellor/Property/Chroot.hs +++ b/src/Propellor/Property/Chroot.hs @@ -19,6 +19,7 @@ import Data.List.Utils import System.Posix.Directory data Chroot = Chroot FilePath System Host + deriving (Show) instance Hostlike Chroot where (Chroot l s h) & p = Chroot l s (h & p) @@ -33,6 +34,7 @@ instance Hostlike Chroot where -- > & ... chroot :: FilePath -> System -> Chroot chroot location system = Chroot location system (Host location [] mempty) + & os system -- | Ensures that the chroot exists and is provisioned according to its -- properties. diff --git a/src/Propellor/Property/Systemd.hs b/src/Propellor/Property/Systemd.hs index 9b0a445d..c6f57e23 100644 --- a/src/Propellor/Property/Systemd.hs +++ b/src/Propellor/Property/Systemd.hs @@ -22,14 +22,12 @@ type ServiceName = String type MachineName = String -type NspawnParam = CommandParam - -data Container = Container MachineName System [CommandParam] Host +data Container = Container MachineName System 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 s h) & p = Container n s (h & p) + (Container n s h) &^ p = Container n s (h &^ p) + getHost (Container _ _ h) = h -- 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 @@ -67,9 +65,12 @@ persistentJournal = check (not <$> doesDirectoryExist dir) $ -- | Defines a container with a given machine name, containing the specified -- System. 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" (System (Debian Unstable) "amd64") +-- > & Apt.installedRunning "apache2" +-- > & ... +container :: MachineName -> System -> Container +container name system = Container name system (Host name [] mempty) + & os system -- | Runs a container using systemd-nspawn. -- @@ -86,7 +87,7 @@ 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 system h) = RevertableProperty setup teardown where setup = combineProperties ("nspawned " ++ name) $ map toProp steps ++ [containerprovisioned] @@ -114,7 +115,7 @@ nspawned c@(Container name system _ h) = RevertableProperty setup teardown chroot = mkChroot 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 @@ -122,7 +123,6 @@ nspawnService (Container name _ ps _) = RevertableProperty setup teardown setup = check (not <$> doesFileExist servicefile) $ started service `requires` enabled service - -- TODO ^ adjust execStart line to reflect ps teardown = undefined @@ -132,7 +132,7 @@ nspawnService (Container name _ ps _) = RevertableProperty setup teardown -- 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 +enterScript c@(Container name _ _) = RevertableProperty setup teardown where setup = combineProperties ("generated " ++ enterScriptFile c) [ scriptfile `File.hasContent` @@ -152,7 +152,7 @@ enterScript c@(Container name _ _ _) = RevertableProperty setup teardown scriptfile = enterScriptFile c enterScriptFile :: Container -> FilePath -enterScriptFile (Container name _ _ _ ) = "/usr/local/bin/enter-" ++ mungename name +enterScriptFile (Container name _ _ ) = "/usr/local/bin/enter-" ++ mungename name enterContainerProcess :: Container -> [String] -> CreateProcess enterContainerProcess = proc . enterScriptFile -- cgit v1.3-2-g0d8e From 9e611d87cd95999eb6b3e5e7f6c855f7c092f57c Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 21 Nov 2014 15:55:27 -0400 Subject: add debootstrap parameters --- config-joey.hs | 4 +-- src/Propellor/Property/Chroot.hs | 56 +++++++++++++++++++++-------------- src/Propellor/Property/Debootstrap.hs | 28 ++++++++++++++++-- src/Propellor/Property/Systemd.hs | 25 +++++++++------- 4 files changed, 75 insertions(+), 38 deletions(-) (limited to 'config-joey.hs') diff --git a/config-joey.hs b/config-joey.hs index a12544df..2971c1a2 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -86,12 +86,12 @@ clam = standardSystem "clam.kitenet.net" Unstable "amd64" & Systemd.nspawned meow meow :: Systemd.Container -meow = Systemd.container "meow" (System (Debian Unstable) "amd64") +meow = Systemd.container "meow" (Chroot.debootstrapped (System (Debian Unstable) "amd64") mempty) & Apt.serviceInstalledRunning "uptimed" & alias "meow.kitenet.net" testChroot :: Chroot.Chroot -testChroot = Chroot.chroot "/tmp/chroot" (System (Debian Unstable) "amd64") +testChroot = Chroot.debootstrapped (System (Debian Unstable) "amd64") mempty "/tmp/chroot" & File.hasContent "/foo" ["hello"] orca :: Host diff --git a/src/Propellor/Property/Chroot.hs b/src/Propellor/Property/Chroot.hs index 2aad26f3..8d4a0364 100644 --- a/src/Propellor/Property/Chroot.hs +++ b/src/Propellor/Property/Chroot.hs @@ -1,6 +1,6 @@ module Propellor.Property.Chroot ( Chroot(..), - chroot, + debootstrapped, provisioned, -- * Internal use provisioned', @@ -18,23 +18,33 @@ import qualified Data.Map as M import Data.List.Utils import System.Posix.Directory -data Chroot = Chroot FilePath System Host +data Chroot = Chroot FilePath System BuilderConf Host + deriving (Show) + +data BuilderConf + = UsingDeboostrap Debootstrap.DebootstrapConfig deriving (Show) instance Hostlike Chroot where - (Chroot l s h) & p = Chroot l s (h & p) - (Chroot l s h) &^ p = Chroot l s (h &^ p) - getHost (Chroot _ _ h) = h + (Chroot l s c h) & p = Chroot l s c (h & p) + (Chroot l s c h) &^ p = Chroot l s c (h &^ p) + getHost (Chroot _ _ _ h) = h --- | Defines a Chroot at the given location, containing the specified --- System. Properties can be added to configure the Chroot. +-- | Defines a Chroot at the given location, built with debootstrap. -- --- > chroot "/srv/chroot/ghc-dev" (System (Debian Unstable) "amd64") --- > & Apt.installed ["build-essential", "ghc", "haskell-platform"] +-- Properties can be added to configure the Chroot. +-- +-- > debootstrapped (System (Debian Unstable) "amd64") Debootstrap.BuildD "/srv/chroot/ghc-dev" +-- > & Apt.installed ["ghc", "haskell-platform"] -- > & ... -chroot :: FilePath -> System -> Chroot -chroot location system = Chroot location system (Host location [] mempty) - & os system +debootstrapped :: System -> Debootstrap.DebootstrapConfig -> FilePath -> Chroot +debootstrapped system conf location = case system of + (System (Debian _) _) -> mk + (System (Ubuntu _) _) -> mk + where + h = Host location [] mempty + mk = Chroot location system (UsingDeboostrap conf) h + & os system -- | Ensures that the chroot exists and is provisioned according to its -- properties. @@ -45,7 +55,7 @@ provisioned :: Chroot -> RevertableProperty provisioned c = provisioned' (propigateChrootInfo c) c provisioned' :: (Property -> Property) -> Chroot -> RevertableProperty -provisioned' propigator c@(Chroot loc system _) = RevertableProperty +provisioned' propigator c@(Chroot loc system builderconf _) = RevertableProperty (propigator $ go "exists" setup) (go "removed" teardown) where @@ -53,11 +63,11 @@ provisioned' propigator c@(Chroot loc system _) = RevertableProperty setup = propellChroot c (inChrootProcess c) `requires` toProp built - built = case system of - (System (Debian _) _) -> debootstrap - (System (Ubuntu _) _) -> debootstrap + built = case (system, builderconf) of + ((System (Debian _) _), UsingDeboostrap cf) -> debootstrap cf + ((System (Ubuntu _) _), UsingDeboostrap cf) -> debootstrap cf - debootstrap = Debootstrap.built loc system [] + debootstrap = Debootstrap.built loc system teardown = toProp (revert built) @@ -65,12 +75,12 @@ propigateChrootInfo :: Chroot -> Property -> Property propigateChrootInfo c p = propigateInfo c p (<> chrootInfo c) chrootInfo :: Chroot -> Info -chrootInfo (Chroot loc _ h) = +chrootInfo (Chroot loc _ _ h) = mempty { _chrootinfo = mempty { _chroots = M.singleton loc h } } -- | Propellor is run inside the chroot to provision it. propellChroot :: Chroot -> ([String] -> CreateProcess) -> Property -propellChroot c@(Chroot loc _ _) mkproc = property (chrootDesc c "provisioned") $ do +propellChroot c@(Chroot loc _ _ _) mkproc = property (chrootDesc c "provisioned") $ do let d = localdir shimdir c let me = localdir "propellor" shim <- liftIO $ ifM (doesDirectoryExist d) @@ -105,7 +115,7 @@ propellChroot c@(Chroot loc _ _) mkproc = property (chrootDesc c "provisioned") processChainOutput toChain :: HostName -> Chroot -> IO CmdLine -toChain parenthost (Chroot loc _ _) = do +toChain parenthost (Chroot loc _ _ _) = do onconsole <- isConsole <$> mkMessageHandle return $ ChrootChain parenthost loc onconsole @@ -124,16 +134,16 @@ chain hostlist hn loc onconsole = case findHostNoAlias hostlist hn of putStrLn $ "\n" ++ show r inChrootProcess :: Chroot -> [String] -> CreateProcess -inChrootProcess (Chroot loc _ _) cmd = proc "chroot" (loc:cmd) +inChrootProcess (Chroot loc _ _ _) cmd = proc "chroot" (loc:cmd) provisioningLock :: FilePath -> FilePath 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 diff --git a/src/Propellor/Property/Debootstrap.hs b/src/Propellor/Property/Debootstrap.hs index 5f521c32..747662c5 100644 --- a/src/Propellor/Property/Debootstrap.hs +++ b/src/Propellor/Property/Debootstrap.hs @@ -1,5 +1,6 @@ module Propellor.Property.Debootstrap ( Url, + DebootstrapConfig(..), built, installed, programPath, @@ -18,6 +19,27 @@ import System.Posix.Directory type Url = String +-- | A monoid for debootstrap configuration. +-- mempty is a default debootstrapped system. +data DebootstrapConfig + = DefaultConfig + | MinBase + | BuilddD + | DebootstrapParam String + | DebootstrapConfig :+ DebootstrapConfig + deriving (Show) + +instance Monoid DebootstrapConfig where + mempty = DefaultConfig + mappend = (:+) + +toParams :: DebootstrapConfig -> [CommandParam] +toParams DefaultConfig = [] +toParams MinBase = [Param "--variant=minbase"] +toParams BuilddD = [Param "--variant=buildd"] +toParams (DebootstrapParam p) = [Param p] +toParams (c1 :+ c2) = toParams c1 <> toParams c2 + -- | Builds a chroot in the given directory using debootstrap. -- -- The System can be any OS and architecture that debootstrap @@ -28,8 +50,8 @@ type Url = String -- -- Note that reverting this property does not stop any processes -- currently running in the chroot. -built :: FilePath -> System -> [CommandParam] -> RevertableProperty -built target system@(System _ arch) extraparams = +built :: FilePath -> System -> DebootstrapConfig -> RevertableProperty +built target system@(System _ arch) config = RevertableProperty setup teardown where setup = check (unpopulated target <||> ispartial) setupprop @@ -44,7 +66,7 @@ built target system@(System _ arch) extraparams = suite <- case extractSuite system of Nothing -> errorMessage $ "don't know how to debootstrap " ++ show system Just s -> pure s - let params = extraparams ++ + let params = toParams config ++ [ Param $ "--arch=" ++ arch , Param suite , Param target diff --git a/src/Propellor/Property/Systemd.hs b/src/Propellor/Property/Systemd.hs index ce7d63c1..d91b441b 100644 --- a/src/Propellor/Property/Systemd.hs +++ b/src/Propellor/Property/Systemd.hs @@ -23,11 +23,11 @@ type ServiceName = String type MachineName = String -data Container = Container MachineName System Host +data Container = Container MachineName Chroot.Chroot Host instance Hostlike Container where - (Container n s h) & p = Container n s (h & p) - (Container n s h) &^ p = Container n s (h &^ p) + (Container n c h) & p = Container n c (h & p) + (Container n c h) &^ p = Container n c (h &^ p) getHost (Container _ _ h) = h -- dbus is only a Recommends of systemd, but is needed for communication @@ -68,15 +68,19 @@ persistentJournal = check (not <$> doesDirectoryExist dir) $ 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. -- --- > container "webserver" (System (Debian Unstable) "amd64") +-- Properties can be added to configure the Container. +-- +-- > container "webserver" (Chroot.debootstrapped (System (Debian Unstable) "amd64") mempty) -- > & Apt.installedRunning "apache2" -- > & ... -container :: MachineName -> System -> Container -container name system = Container name system (Host name [] mempty) +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. -- @@ -93,7 +97,8 @@ container name system = Container name system (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 setup = combineProperties ("nspawned " ++ name) $ map toProp steps ++ [containerprovisioned] @@ -117,7 +122,7 @@ nspawned c@(Container name system h) = RevertableProperty setup teardown containerprovisioned = Chroot.propellChroot chroot (enterContainerProcess c) - mkChroot = Chroot.Chroot (containerDir name) system + mkChroot = Chroot.Chroot loc system builderconf chroot = mkChroot h nspawnService :: Container -> RevertableProperty -- cgit v1.3-2-g0d8e From c4accb72e20bc0906c1089c60574b844234d6401 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 21 Nov 2014 15:56:50 -0400 Subject: propellor spin --- config-joey.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'config-joey.hs') diff --git a/config-joey.hs b/config-joey.hs index 2971c1a2..a2a501a7 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -83,7 +83,7 @@ clam = standardSystem "clam.kitenet.net" Unstable "amd64" ! Chroot.provisioned testChroot & Systemd.persistentJournal - & Systemd.nspawned meow + ! Systemd.nspawned meow meow :: Systemd.Container meow = Systemd.container "meow" (Chroot.debootstrapped (System (Debian Unstable) "amd64") mempty) -- cgit v1.3-2-g0d8e From 7a6f277ccb99bf33d0f6a3f90cd809bb39031c9c Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 21 Nov 2014 16:04:02 -0400 Subject: propellor spin --- config-joey.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'config-joey.hs') diff --git a/config-joey.hs b/config-joey.hs index a2a501a7..2971c1a2 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -83,7 +83,7 @@ clam = standardSystem "clam.kitenet.net" Unstable "amd64" ! Chroot.provisioned testChroot & Systemd.persistentJournal - ! Systemd.nspawned meow + & Systemd.nspawned meow meow :: Systemd.Container meow = Systemd.container "meow" (Chroot.debootstrapped (System (Debian Unstable) "amd64") mempty) -- cgit v1.3-2-g0d8e From a6c7e228625456cb267b6fa4b9f75e2cbc067f0d Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 21 Nov 2014 17:16:30 -0400 Subject: propellor spin --- config-joey.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'config-joey.hs') diff --git a/config-joey.hs b/config-joey.hs index 2971c1a2..a2a501a7 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -83,7 +83,7 @@ clam = standardSystem "clam.kitenet.net" Unstable "amd64" ! Chroot.provisioned testChroot & Systemd.persistentJournal - & Systemd.nspawned meow + ! Systemd.nspawned meow meow :: Systemd.Container meow = Systemd.container "meow" (Chroot.debootstrapped (System (Debian Unstable) "amd64") mempty) -- cgit v1.3-2-g0d8e From 04ea987075b869ea70cf55a193af7f5604ff0561 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 21 Nov 2014 17:19:00 -0400 Subject: propellor spin --- config-joey.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'config-joey.hs') diff --git a/config-joey.hs b/config-joey.hs index a2a501a7..2971c1a2 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -83,7 +83,7 @@ clam = standardSystem "clam.kitenet.net" Unstable "amd64" ! Chroot.provisioned testChroot & Systemd.persistentJournal - ! Systemd.nspawned meow + & Systemd.nspawned meow meow :: Systemd.Container meow = Systemd.container "meow" (Chroot.debootstrapped (System (Debian Unstable) "amd64") mempty) -- cgit v1.3-2-g0d8e