@@ -5,10 +5,9 @@
55module Obelisk.Command.VmBuilder where
66
77import Control.Applicative (liftA2)
8−import Control.Monad (unless)
9−import Control.Monad.Catch (try, handle)
8+import Control.Monad (when, unless)
9+import Control.Monad.Catch (handle)
1010import Control.Monad.IO.Class (liftIO)
11−import Data.Either (isRight)
1211import Data.Monoid ((<>))
1312import Data.String (IsString)
1413import Data.String.Here.Uninterpolated (hereLit)
@@ -16,7 +15,7 @@ import Data.Text (Text)
1615import qualified Data.Text as T
1716import qualified Data.Text.IO as T
1817import System.Directory (createDirectoryIfMissing)
19−import System.Exit (ExitCode)
18+import System.Exit (ExitCode(..))
2019import System.FilePath ((<.>), (</>))
2120import qualified System.Info
2221import System.Process (proc)
@@ -29,7 +28,7 @@ import Obelisk.Command.Nix (withNixRemoteCheck)
2928getNixBuildersArg :: MonadObelisk m => m String
3029getNixBuildersArg = do
3130 stateDir <- liftIO getDockerBuilderStateDir
32− exists <- containerExists
31+ exists <- containerExists stateDir
3332 if exists then startContainer else setupNixDocker stateDir
3433 pure $ nixBuildersArgString stateDir
3534
@@ -42,12 +41,14 @@ containerName :: IsString str => str
4241containerName = "obelisk-docker-nix-builder"
4342
4443-- | Check to see if the Docker container exists. This will exit with a helpful message if Docker is not installed.
45−containerExists :: MonadObelisk m => m Bool
46−containerExists = handle (\(_ :: IOError) -> failWith needDockerMsg) $ do
44+containerExists :: MonadObelisk m => FilePath -> m Bool
45+containerExists stateDir = handle (\(_ :: IOError) -> failWith needDockerMsg) $ do
4746 containerNames <- fmap (map T.strip . T.lines) $
4847 readProcessAndLogStderr Error $
4948 proc "docker" ["container", "list", "--all", "--format", "{{.Names}}"]
50− pure $ containerName `elem` containerNames
49+ let exists = containerName `elem` containerNames
50+ when exists $ testLinuxBuild stateDir
51+ pure exists
5152 where
5253 needDockerMsg = T.intercalate "\n"
5354 [ "This feature requires that you have Docker installed and the `docker` command available on your PATH."
@@ -87,16 +88,11 @@ setupNixDocker stateDir = withSpinner ("Creating Docker container named " <> con
8788 , "--publish", show containerSshPort <> ":22"
8889 , "--name", T.unpack containerName, T.unpack containerId
8990 ]
90− exists <- containerExists
91+ exists <- containerExists stateDir
9192 unless exists $
9293 failWith $ "Expected to see docker container named " <> containerName <> " but it does not exist."
9394
94− linuxBuildWorked <- if System.Info.os == "linux"
95− then pure False -- The Linux test is useless on Linux so just assume the setup is incomplete.
96− else testLinuxBuild stateDir
97− unless linuxBuildWorked $ do
98− let sshIdFile = stateDir </> sshKeyFileName
99− failWith $ setupInstructions sshIdFile
95+ testLinuxBuild stateDir
10096
10197-- | The instructions for setting up SSH access to the container for the Nix daemon.
10298setupInstructions :: FilePath -> Text
@@ -133,13 +129,18 @@ getDockerBuilderStateDir :: IO FilePath
133129getDockerBuilderStateDir = liftA2 (</>) getObeliskUserStateDir (pure "nix-docker-builder")
134130
135131-- | Run a test build to see if a Linux build can finish successfully.
136−testLinuxBuild :: MonadObelisk m => FilePath -> m Bool
137−testLinuxBuild stateDir =
138− fmap (isRight :: Either ExitCode () -> Bool) $ try $ withNixRemoteCheck $
139− callProcessAndLogOutput (Debug, Debug) $ proc "nix-build"
140− [ "-E", "(import <nixpkgs> { system = \"x86_64-linux\"; }).writeText \"test\" builtins.currentTime"
141− , "--builders", nixBuildersArgString stateDir
142− ]
132+testLinuxBuild :: MonadObelisk m => FilePath -> m ()
133+testLinuxBuild stateDir
134+ | System.Info.os == "linux" = failWith "Using the docker builder is not necessary on linux."
135+ | otherwise = withNixRemoteCheck $ do
136+ (exitCode, _stdout, stderr) <- readCreateProcessWithExitCode $ proc "nix-build"
137+ [ "-E", "(import <nixpkgs> { system = \"x86_64-linux\"; }).writeText \"test\" builtins.currentTime"
138+ , "--builders", nixBuildersArgString stateDir
139+ ]
140+ unless (exitCode == ExitSuccess) $ do
141+ let sshIdFile = stateDir </> sshKeyFileName
142+ putLog Error $ T.pack stderr
143+ failWith $ setupInstructions sshIdFile
143144
144145-- Copied from https://raw.githubusercontent.com/LnL7/nix-docker/bf28b99aebd8e403d2fc2171f4fa8878f857171c/ssh/Dockerfile
145146-- Renamed "insecure_rsa" to 'sshKeyFileName'