module B9.B9Config.SystemdNspawn ( systemdNspawnConfigToCPDocument, defaultSystemdNspawnConfig, parseSystemdNspawnConfig, SystemdNspawnConfig (..), SystemdNspawnConsole (..), systemdNspawnCapabilities, systemdNspawnUseSudo, systemdNspawnMaxLifetimeSeconds, systemdNspawnExtraArgs, systemdNspawnExecutable, systemdNspawnConsole, ) where import B9.B9Config.Container import Control.Lens (makeLenses) import Data.ConfigFile.B9Extras import qualified Text.ParserCombinators.ReadP as ReadP import qualified Text.ParserCombinators.ReadPrec as ReadPrec import Text.Read import Test.QuickCheck (Arbitrary(arbitrary)) import qualified Test.QuickCheck as QuickCheck import B9.QCUtil (smaller, arbitraryFilePath) -- TODO document b9 config file data SystemdNspawnConfig = SystemdNspawnConfig { _systemdNspawnCapabilities :: [ContainerCapability], _systemdNspawnUseSudo :: Bool, _systemdNspawnMaxLifetimeSeconds :: Maybe Int, _systemdNspawnExtraArgs :: Maybe String, _systemdNspawnExecutable :: Maybe FilePath, _systemdNspawnConsole :: SystemdNspawnConsole } deriving (Read, Show, Eq) instance Arbitrary SystemdNspawnConfig where arbitrary = SystemdNspawnConfig <$> smaller arbitrary <*> smaller arbitrary <*> smaller arbitrary <*> smaller arbitrary <*> smaller (QuickCheck.oneof [pure Nothing, Just <$> arbitraryFilePath]) <*> smaller arbitrary data SystemdNspawnConsole = SystemdNspawnInteractive | SystemdNspawnReadOnly | SystemdNspawnPassive | SystemdNspawnPipe deriving (Eq) instance Arbitrary SystemdNspawnConsole where arbitrary = QuickCheck.elements [ SystemdNspawnInteractive , SystemdNspawnReadOnly , SystemdNspawnPassive , SystemdNspawnPipe ] instance Show SystemdNspawnConsole where show x = case x of SystemdNspawnInteractive -> "interactive" SystemdNspawnReadOnly -> "read-only" SystemdNspawnPassive -> "passive" SystemdNspawnPipe -> "pipe" instance Read SystemdNspawnConsole where readPrec = do Ident "interactive" <- lexP return SystemdNspawnInteractive +++ ReadPrec.lift ( do ReadP.skipSpaces _ <- ReadP.string "read-only" return SystemdNspawnReadOnly ) +++ do Ident "passive" <- lexP return SystemdNspawnPassive +++ do Ident "pipe" <- lexP return SystemdNspawnPipe makeLenses ''SystemdNspawnConfig defaultSystemdNspawnConfig :: SystemdNspawnConfig defaultSystemdNspawnConfig = SystemdNspawnConfig [ CAP_MKNOD, CAP_SYS_ADMIN, CAP_SYS_CHROOT, CAP_SETGID, CAP_SETUID, CAP_NET_BIND_SERVICE, CAP_SETPCAP, CAP_SYS_PTRACE, CAP_SYS_MODULE ] True (Just (4 * 3600)) Nothing Nothing SystemdNspawnReadOnly cfgFileSection :: String cfgFileSection = "systemdNspawn" useSudoK :: String useSudoK = "use_sudo" maxLifetimeSecondsK :: String maxLifetimeSecondsK = "max_lifetime_seconds" extraArgsK :: String extraArgsK = "extra_args" executableK :: String executableK = "executable" consoleK :: String consoleK = "console" systemdNspawnConfigToCPDocument :: SystemdNspawnConfig -> CPDocument -> Either CPError CPDocument systemdNspawnConfigToCPDocument c cp = do cp1 <- addSectionCP cp cfgFileSection cp2 <- containerCapsToCPDocument cp1 cfgFileSection $ _systemdNspawnCapabilities c cp3 <- setShowCP cp2 cfgFileSection useSudoK $ _systemdNspawnUseSudo c cp4 <- setShowCP cp3 cfgFileSection maxLifetimeSecondsK $ _systemdNspawnMaxLifetimeSeconds c cp5 <- setShowCP cp4 cfgFileSection extraArgsK $ _systemdNspawnExtraArgs c cp6 <- setShowCP cp5 cfgFileSection executableK $ _systemdNspawnExecutable c setShowCP cp6 cfgFileSection consoleK $ _systemdNspawnConsole c parseSystemdNspawnConfig :: CPDocument -> Either CPError SystemdNspawnConfig parseSystemdNspawnConfig cp = let getr :: (CPGet a) => CPOptionSpec -> Either CPError a getr = readCP cp cfgFileSection in SystemdNspawnConfig <$> parseContainerCapabilities cp cfgFileSection <*> getr useSudoK <*> getr maxLifetimeSecondsK <*> getr extraArgsK <*> getr executableK <*> getr consoleK