Use dockerTools.streamLayeredImage if available
Technically this opens a new attack vector, but if you don't trust the code you're deploying, you should already have taken precautions because of nix-shell, direnv etc. This just adds arion to that list.
This commit is contained in:
parent
88c361c81c
commit
067ce26177
3 changed files with 44 additions and 8 deletions
|
@ -17,7 +17,8 @@ import Control.Lens
|
||||||
import Data.Aeson.Lens
|
import Data.Aeson.Lens
|
||||||
|
|
||||||
data Image = Image
|
data Image = Image
|
||||||
{ image :: Text -- ^ file path
|
{ image :: Maybe Text -- ^ image tar.gz file path
|
||||||
|
, imageExe :: Maybe Text -- ^ path to exe producing image tar
|
||||||
, imageName :: Text
|
, imageName :: Text
|
||||||
, imageTag :: Text
|
, imageTag :: Text
|
||||||
} deriving (Generic, Aeson.ToJSON, Aeson.FromJSON, Show)
|
} deriving (Generic, Aeson.ToJSON, Aeson.FromJSON, Show)
|
||||||
|
@ -38,10 +39,11 @@ loadImages fp = do
|
||||||
|
|
||||||
isNew i = (imageName i <> ":" <> imageTag i) `notElem` loaded
|
isNew i = (imageName i <> ":" <> imageTag i) `notElem` loaded
|
||||||
|
|
||||||
traverse_ loadImage . map (toS . image) . filter isNew $ images
|
traverse_ loadImage . filter isNew $ images
|
||||||
|
|
||||||
loadImage :: FilePath -> IO ()
|
loadImage :: Image -> IO ()
|
||||||
loadImage imgPath = withFile (imgPath) ReadMode $ \fileHandle -> do
|
loadImage (Image { image = Just imgPath, imageName = name }) =
|
||||||
|
withFile (toS imgPath) ReadMode $ \fileHandle -> do
|
||||||
let procSpec = (Process.proc "docker" [ "load" ]) {
|
let procSpec = (Process.proc "docker" [ "load" ]) {
|
||||||
Process.std_in = Process.UseHandle fileHandle
|
Process.std_in = Process.UseHandle fileHandle
|
||||||
}
|
}
|
||||||
|
@ -49,7 +51,29 @@ loadImage imgPath = withFile (imgPath) ReadMode $ \fileHandle -> do
|
||||||
e <- Process.waitForProcess procHandle
|
e <- Process.waitForProcess procHandle
|
||||||
case e of
|
case e of
|
||||||
ExitSuccess -> pass
|
ExitSuccess -> pass
|
||||||
ExitFailure code -> panic $ "docker load (" <> show code <> ") failed for " <> toS imgPath
|
ExitFailure code ->
|
||||||
|
panic $ "docker 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 }
|
||||||
|
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 ->
|
||||||
|
withAsync (Process.waitForProcess loadProcHandle) $ \loadExitAsync ->
|
||||||
|
withAsync (Process.waitForProcess streamProcHandle) $ \streamExitAsync -> do
|
||||||
|
r <- waitEither loadExitAsync streamExitAsync
|
||||||
|
case r of
|
||||||
|
Right (ExitFailure code) -> panic $ "image producer for image " <> name <> " failed with exit code " <> show code <> " from executable " <> imgExe
|
||||||
|
Right ExitSuccess -> pass
|
||||||
|
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
|
||||||
|
_ -> pass
|
||||||
|
pass
|
||||||
|
|
||||||
|
loadImage (Image { imageName = name }) = do
|
||||||
|
panic $ "image " <> name <> " doesn't specify an image file or imageExe executable"
|
||||||
|
|
||||||
|
|
||||||
getDockerImages :: IO [TaggedImage]
|
getDockerImages :: IO [TaggedImage]
|
||||||
|
|
|
@ -16,13 +16,20 @@ let
|
||||||
(let
|
(let
|
||||||
inherit (service) build;
|
inherit (service) build;
|
||||||
in {
|
in {
|
||||||
image = build.image.outPath;
|
|
||||||
imageName = build.imageName or service.image.name;
|
imageName = build.imageName or service.image.name;
|
||||||
imageTag =
|
imageTag =
|
||||||
if build.image.imageTag != ""
|
if build.image.imageTag != ""
|
||||||
then build.image.imageTag
|
then build.image.imageTag
|
||||||
else lib.head (lib.strings.splitString "-" (baseNameOf build.image.outPath));
|
else lib.head (lib.strings.splitString "-" (baseNameOf build.image.outPath));
|
||||||
});
|
} // (if build.image.isExe or false
|
||||||
|
then {
|
||||||
|
imageExe = build.image.outPath;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
image = build.image.outPath;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
|
|
|
@ -9,7 +9,12 @@ let
|
||||||
(pkgs.writeText "dummy-config.json" (builtins.toJSON config.image.rawConfig))
|
(pkgs.writeText "dummy-config.json" (builtins.toJSON config.image.rawConfig))
|
||||||
];
|
];
|
||||||
|
|
||||||
builtImage = pkgs.dockerTools.buildLayeredImage {
|
buildOrStreamLayeredImage = args:
|
||||||
|
if pkgs.dockerTools?streamLayeredImage
|
||||||
|
then pkgs.dockerTools.streamLayeredImage args // { isExe = true; }
|
||||||
|
else pkgs.dockerTools.buildLayeredImage args;
|
||||||
|
|
||||||
|
builtImage = buildOrStreamLayeredImage {
|
||||||
inherit (config.image)
|
inherit (config.image)
|
||||||
name
|
name
|
||||||
contents
|
contents
|
||||||
|
|
Loading…
Reference in a new issue