WIP podman

This commit is contained in:
Robert Hensing 2021-05-18 18:46:42 +02:00
parent 01f359b8f6
commit 3dcadd5e40
8 changed files with 67 additions and 26 deletions

View file

@ -1,4 +1,6 @@
{
deployment.technology = "podman";
services.webserver = { pkgs, lib, ... }: {
nixos.useSystemd = true;
nixos.configuration.boot.tmpOnTmpfs = true;

View file

@ -48,6 +48,8 @@ in
haskellPkgs.ghcid
haskellPkgs.haskell-language-server
super.docker-compose
super.podman
super.podman-compose
self.niv
self.releaser
];

View file

@ -10,7 +10,7 @@ import Arion.Aeson
import Arion.Images (loadImages)
import qualified Arion.DockerCompose as DockerCompose
import Arion.Services (getDefaultExec)
import Arion.ExtendedInfo (loadExtendedInfoFromPath, ExtendedInfo(images, projectName))
import Arion.ExtendedInfo (loadExtendedInfoFromPath, ExtendedInfo(images, projectName), technology, Technology(..))
import Options.Applicative
import Control.Monad.Fail
@ -147,6 +147,7 @@ runDC cmd (DockerComposeArgs args) _opts = do
DockerCompose.run DockerCompose.Args
{ files = []
, otherArgs = [cmd] ++ args
, isPodman = True -- FIXME
}
runBuildAndDC :: Text -> DockerComposeArgs -> CommonOptions -> IO ()
@ -160,11 +161,13 @@ runEvalAndDC cmd dopts opts = do
callDC :: Text -> DockerComposeArgs -> CommonOptions -> Bool -> FilePath -> IO ()
callDC cmd dopts opts shouldLoadImages path = do
extendedInfo <- loadExtendedInfoFromPath path
when shouldLoadImages $ loadImages (images extendedInfo)
let is_podman = technology extendedInfo == Podman
when shouldLoadImages $ loadImages is_podman (images extendedInfo)
let firstOpts = projectArgs extendedInfo <> commonArgs opts
DockerCompose.run DockerCompose.Args
{ files = [path]
, otherArgs = firstOpts ++ [cmd] ++ unDockerComposeArgs dopts
, isPodman = is_podman
}
projectArgs :: ExtendedInfo -> [Text]
@ -299,6 +302,7 @@ runExec detach privileged user noTTY index envs workDir service commandAndArgs o
[] -> ["/bin/sh"]
x -> x
let is_podman = technology extendedInfo == Podman
let args = concat
[ ["exec"]
, ("--detach" <$ guard detach :: [Text])
@ -314,6 +318,7 @@ runExec detach privileged user noTTY index envs workDir service commandAndArgs o
DockerCompose.run DockerCompose.Args
{ files = [path]
, otherArgs = projectArgs extendedInfo <> commonArgs opts <> args
, isPodman = is_podman
}
main :: IO ()

View file

@ -8,6 +8,7 @@ import System.Process
data Args = Args
{ files :: [FilePath]
, otherArgs :: [Text]
, isPodman :: Bool
}
run :: Args -> IO ()
@ -15,9 +16,9 @@ run args = do
let fileArgs = files args >>= \f -> ["--file", f]
allArgs = fileArgs ++ map toS (otherArgs args)
procSpec = proc "docker-compose" allArgs
-- hPutStrLn stderr ("Running docker-compose with " <> show allArgs :: Text)
exeName = if isPodman args then "podman-compose" else "docker-compose"
procSpec =
proc exeName allArgs
withCreateProcess procSpec $ \_in _out _err procHandle -> do
@ -27,4 +28,4 @@ run args = do
ExitSuccess -> pass
ExitFailure 1 -> exitFailure
ExitFailure {} -> do
throwIO $ FatalError $ "docker-compose failed with " <> show exitCode
throwIO $ FatalError $ toS exeName <> " failed with status " <> show exitCode

View file

@ -22,9 +22,13 @@ data Image = Image
, imageTag :: Text
} deriving (Eq, Show, Generic, Aeson.ToJSON, Aeson.FromJSON)
data Technology = Docker | Podman
deriving (Eq, Show)
data ExtendedInfo = ExtendedInfo {
projectName :: Maybe Text,
images :: [Image]
images :: [Image],
technology :: Technology
} deriving (Eq, Show)
loadExtendedInfoFromPath :: FilePath -> IO ExtendedInfo
@ -33,5 +37,10 @@ loadExtendedInfoFromPath fp = do
pure ExtendedInfo {
-- TODO: use aeson derived instance?
projectName = v ^? key "x-arion" . key "project" . key "name" . _String,
images = (v :: Aeson.Value) ^.. key "x-arion" . key "images" . _Array . traverse . _JSON
images = (v :: Aeson.Value) ^.. key "x-arion" . key "images" . _Array . traverse . _JSON,
technology =
case v ^? key "x-arion" . key "technology" . _String of
Just "podman" -> Podman
Just "docker" -> Docker
_ -> panic "Unknown x-arion.technology" -- Shouldn't happen
}

View file

@ -16,10 +16,10 @@ import Arion.ExtendedInfo (Image(..))
type TaggedImage = Text
-- | Subject to change
loadImages :: [Image] -> IO ()
loadImages requestedImages = do
loadImages :: Bool -> [Image] -> IO ()
loadImages isPodman requestedImages = do
loaded <- getDockerImages
loaded <- getDockerImages isPodman
let
isNew i =
@ -28,23 +28,28 @@ loadImages requestedImages = do
-- -- On podman, you automatically get a localhost prefix
&& ("localhost/" <> imageName i <> ":" <> imageTag i) `notElem` loaded
traverse_ loadImage . filter isNew $ requestedImages
traverse_ (loadImage isPodman) . filter isNew $ requestedImages
loadImage :: Image -> IO ()
loadImage Image { image = Just imgPath, imageName = name } =
exeName :: IsString p => Bool -> p
exeName _isPodman@True = "podman"
exeName _isPodman@False = "docker"
loadImage :: Bool -> Image -> IO ()
loadImage isPodman Image { image = Just imgPath, imageName = name } =
withFile (toS imgPath) ReadMode $ \fileHandle -> do
let procSpec = (Process.proc "docker" [ "load" ]) {
let procSpec = (Process.proc (exeName isPodman) [ "load" ]) {
Process.std_in = Process.UseHandle fileHandle
}
print procSpec
Process.withCreateProcess procSpec $ \_in _out _err procHandle -> do
e <- Process.waitForProcess procHandle
case e of
ExitSuccess -> pass
ExitFailure code ->
panic $ "docker load failed with exit code " <> show code <> " for image " <> name <> " from path " <> imgPath
panic $ exeName isPodman <> " load failed with exit code " <> show code <> " for image " <> name <> " from path " <> imgPath
loadImage Image { imageExe = Just imgExe, imageName = name } = do
let loadSpec = (Process.proc "docker" [ "load" ]) { Process.std_in = Process.CreatePipe }
loadImage isPodman Image { imageExe = Just imgExe, imageName = name } = do
let loadSpec = (Process.proc (exeName isPodman) [ "load" ]) { Process.std_in = Process.CreatePipe }
Process.withCreateProcess loadSpec $ \(Just inHandle) _out _err loadProcHandle -> do
let streamSpec = Process.proc (toS imgExe) []
Process.withCreateProcess streamSpec { Process.std_out = Process.UseHandle inHandle } $ \_ _ _ streamProcHandle ->
@ -57,15 +62,15 @@ loadImage Image { imageExe = Just imgExe, imageName = name } = do
Left _ -> pass
loadExit <- wait loadExitAsync
case loadExit of
ExitFailure code -> panic $ "docker load failed with exit code " <> show code <> " for image " <> name <> " produced by executable " <> imgExe
ExitFailure code -> panic $ exeName isPodman <> " load failed with exit code " <> show code <> " for image " <> name <> " produced by executable " <> imgExe
_ -> pass
pass
loadImage Image { imageName = name } = do
loadImage _isPodman Image { imageName = name } = do
panic $ "image " <> name <> " doesn't specify an image file or imageExe executable"
getDockerImages :: IO [TaggedImage]
getDockerImages = do
let procSpec = Process.proc "docker" [ "images", "--filter", "dangling=false", "--format", "{{.Repository}}:{{.Tag}}" ]
getDockerImages :: Bool -> IO [TaggedImage]
getDockerImages isPodman = do
let procSpec = Process.proc (exeName isPodman) [ "images", "--filter", "dangling=false", "--format", "{{.Repository}}:{{.Tag}}" ]
map toS . T.lines . toS <$> Process.readCreateProcess procSpec ""

View file

@ -4,4 +4,7 @@
./modules/composition/images.nix
./modules/composition/service-info.nix
./modules/composition/composition.nix
./modules/composition/deployment.nix
./modules/composition/deployment/docker.nix
./modules/composition/deployment/podman.nix
]

View file

@ -29,6 +29,20 @@ let
config.service.name = name;
};
json.type = with lib.types; let
valueType = nullOr (oneOf [
bool
int
float
str
path # extra
package # extra
(attrsOf valueType)
(listOf valueType)
]) // {
description = "JSON value";
};
in valueType;
in
{
imports = [
@ -52,11 +66,11 @@ in
readOnly = true;
};
docker-compose.raw = lib.mkOption {
type = lib.types.attrs;
type = json.type;
description = "Attribute set that will be turned into the docker-compose.yaml file, using Nix's toJSON builtin.";
};
docker-compose.extended = lib.mkOption {
type = lib.types.attrs;
type = json.type;
description = "Attribute set that will be turned into the x-arion section of the docker-compose.yaml file.";
};
services = lib.mkOption {