diff --git a/sandwich-contexts-docker/lib/Test/Sandwich/Contexts/Docker/Container.hs b/sandwich-contexts-docker/lib/Test/Sandwich/Contexts/Docker/Container.hs index 81651b5..152c209 100644 --- a/sandwich-contexts-docker/lib/Test/Sandwich/Contexts/Docker/Container.hs +++ b/sandwich-contexts-docker/lib/Test/Sandwich/Contexts/Docker/Container.hs @@ -10,8 +10,6 @@ module Test.Sandwich.Contexts.Docker.Container ( , containerNameToContainerId - , readUncompressedImageName - , waitForHealth ) where @@ -22,19 +20,15 @@ import Control.Monad.Trans.Control (MonadBaseControl) import Control.Retry import Data.Aeson as A import Data.Aeson.TH as A -import qualified Data.ByteString.Lazy as BL import qualified Data.List as L import qualified Data.Map as M import Data.String.Interpolate import qualified Data.Text as T -import qualified Data.Vector as V import Network.Socket (PortNumber) import Relude import Safe import System.Exit -import System.FilePath import Test.Sandwich -import Test.Sandwich.Contexts.Util.Aeson (aesonLookup) import qualified Text.Show import UnliftIO.Process @@ -108,19 +102,3 @@ containerNameToContainerId containerSystem containerName = do liftIO (readCreateProcessWithExitCode (shell cmd) "") >>= \case (ExitSuccess, sout, _serr) -> return $ T.strip $ toText sout (ExitFailure n, sout, serr) -> expectationFailure [i|Failed to obtain container ID for container named '#{containerName}'. Code: #{n}. Stdout: '#{sout}'. Stderr: '#{serr}'.|] - -readUncompressedImageName :: (HasCallStack, MonadIO m) => FilePath -> m Text -readUncompressedImageName path = do - contents <- liftIO $ BL.readFile (path "manifest.json") - - case A.eitherDecode contents of - Left err -> expectationFailure [i|Couldn't decode manifest.json: #{err}|] - Right (A.Array entries) -> case concatMap getRepoTags entries of - (x:_) -> pure x - [] -> expectationFailure [i|Didn't find a repo tag for image at #{path}|] - Right x -> expectationFailure [i|Unexpected manifest.json format: #{x}|] - - where - getRepoTags :: A.Value -> [Text] - getRepoTags (A.Object (aesonLookup "RepoTags" -> Just (A.Array repoItems))) = [t | A.String t <- V.toList repoItems] - getRepoTags _ = [] diff --git a/sandwich-contexts-kubernetes/lib/Sandwich/Contexts/Kubernetes/MinikubeCluster/Images.hs b/sandwich-contexts-kubernetes/lib/Sandwich/Contexts/Kubernetes/MinikubeCluster/Images.hs index 8c87054..939ecd4 100644 --- a/sandwich-contexts-kubernetes/lib/Sandwich/Contexts/Kubernetes/MinikubeCluster/Images.hs +++ b/sandwich-contexts-kubernetes/lib/Sandwich/Contexts/Kubernetes/MinikubeCluster/Images.hs @@ -69,7 +69,7 @@ withLoadImages' kcc@(KubernetesClusterContext {kubernetesClusterType=(Kubernetes |] debug [i|withLoadImages': #{cmd}|] createProcessWithLogging (shell cmd) >>= waitForProcess >>= (`shouldBe` ExitSuccess) - tweak <$> readUncompressedImageName (toString image) + tweak <$> readImageName (toString image) False -> do let cmd = [iii|minikube image load #{image} diff --git a/sandwich-contexts-kubernetes/lib/Sandwich/Contexts/Kubernetes/Util/Container.hs b/sandwich-contexts-kubernetes/lib/Sandwich/Contexts/Kubernetes/Util/Container.hs index 6c6d846..de3ee3d 100644 --- a/sandwich-contexts-kubernetes/lib/Sandwich/Contexts/Kubernetes/Util/Container.hs +++ b/sandwich-contexts-kubernetes/lib/Sandwich/Contexts/Kubernetes/Util/Container.hs @@ -10,12 +10,12 @@ module Sandwich.Contexts.Kubernetes.Util.Container ( , containerNameToContainerId + , readImageName , readUncompressedImageName , waitForHealth ) where -import Sandwich.Contexts.Kubernetes.Util.Aeson import Control.Monad.Catch import Control.Monad.IO.Unlift import Control.Monad.Logger @@ -32,11 +32,14 @@ import qualified Data.Vector as V import Network.Socket (PortNumber) import Relude import Safe +import Sandwich.Contexts.Kubernetes.Util.Aeson import System.Exit import System.FilePath import Test.Sandwich import qualified Text.Show +import UnliftIO.Directory import UnliftIO.Process +import UnliftIO.Temporary data ContainerSystem = ContainerSystemDocker | ContainerSystemPodman @@ -110,9 +113,28 @@ containerNameToContainerId containerSystem containerName = do (ExitFailure n, sout, serr) -> expectationFailure [i|Failed to obtain container ID for container named '#{containerName}'. Code: #{n}. Stdout: '#{sout}'. Stderr: '#{serr}'.|] readUncompressedImageName :: (HasCallStack, MonadIO m) => FilePath -> m Text -readUncompressedImageName path = do - contents <- liftIO $ BL.readFile (path "manifest.json") +readUncompressedImageName path = liftIO (BL.readFile (path "manifest.json")) >>= getImageNameFromManifestJson path +readImageName :: (HasCallStack, MonadUnliftIO m, MonadLogger m) => FilePath -> m Text +readImageName path = doesDirectoryExist path >>= \case + True -> readUncompressedImageName path + False -> case takeExtension path of + ".tar" -> extractFromTarball + ".gz" -> extractFromTarball + _ -> expectationFailure [i|readImageName: unexpected extension in #{path}. Wanted .tar, .tar.gz, or uncompressed directory.|] + where + extractFromTarball = do + files <- readCreateProcessWithLogging (proc "tar" ["tf", path]) "" + manifestFileName <- case headMay [t | t <- T.words (toText files), "manifest.json" `T.isInfixOf` t] of + Just f -> pure $ toString $ T.strip f + Nothing -> expectationFailure [i|readImageName: couldn't find manifest file in #{path}|] + + withSystemTempDirectory "manifest.json" $ \dir -> do + _ <- readCreateProcessWithLogging ((proc "tar" ["xvf", path, manifestFileName]) { cwd = Just dir }) "" + liftIO (BL.readFile (dir "manifest.json")) >>= getImageNameFromManifestJson path + +getImageNameFromManifestJson :: (HasCallStack, MonadIO m) => FilePath -> LByteString -> m Text +getImageNameFromManifestJson path contents = do case A.eitherDecode contents of Left err -> expectationFailure [i|Couldn't decode manifest.json: #{err}|] Right (A.Array entries) -> case concatMap getRepoTags entries of diff --git a/sandwich-contexts/lib/Test/Sandwich/Contexts/Util/Container.hs b/sandwich-contexts/lib/Test/Sandwich/Contexts/Util/Container.hs index 0aa94c9..fcfc6cf 100644 --- a/sandwich-contexts/lib/Test/Sandwich/Contexts/Util/Container.hs +++ b/sandwich-contexts/lib/Test/Sandwich/Contexts/Util/Container.hs @@ -10,8 +10,6 @@ module Test.Sandwich.Contexts.Util.Container ( , containerNameToContainerId - , readUncompressedImageName - , waitForHealth ) where @@ -30,10 +28,10 @@ import qualified Data.Vector as V import Network.Socket (PortNumber) import Relude import Safe -import Test.Sandwich.Contexts.Util.Aeson import System.Exit import System.FilePath import Test.Sandwich +import Test.Sandwich.Contexts.Util.Aeson import qualified Text.Show import UnliftIO.Process @@ -107,19 +105,3 @@ containerNameToContainerId containerSystem containerName = do liftIO (readCreateProcessWithExitCode (shell cmd) "") >>= \case (ExitSuccess, sout, _serr) -> return $ T.strip $ toText sout (ExitFailure n, sout, serr) -> expectationFailure [i|Failed to obtain container ID for container named '#{containerName}'. Code: #{n}. Stdout: '#{sout}'. Stderr: '#{serr}'.|] - -readUncompressedImageName :: (HasCallStack, MonadIO m) => FilePath -> m Text -readUncompressedImageName path = do - contents <- liftIO $ BL.readFile (path "manifest.json") - - case A.eitherDecode contents of - Left err -> expectationFailure [i|Couldn't decode manifest.json: #{err}|] - Right (A.Array entries) -> case concatMap getRepoTags entries of - (x:_) -> pure x - [] -> expectationFailure [i|Didn't find a repo tag for image at #{path}|] - Right x -> expectationFailure [i|Unexpected manifest.json format: #{x}|] - - where - getRepoTags :: A.Value -> [Text] - getRepoTags (A.Object (aesonLookup "RepoTags" -> Just (A.Array repoItems))) = [t | A.String t <- V.toList repoItems] - getRepoTags _ = []