on master help sign in
Merge pull request #658 from obsidiansystems/eac@config-deploy-module

Support non-EC2 targets with ob deploy

commit9db8523ed9d998d4e9e79b405f26210434de92ff authorElliot Cameron <3noch@users.noreply.github.com> dateThu 12 Mar 2020, 16:20 (7 years ago) parent3f0d2828542426
4 files changed+52−34
default.nix+11−6 lib/command/src/Obelisk/Command.hs+2−2 lib/command/src/Obelisk/Command/Deploy.hs+36−26 lib/command/src/Obelisk/Command/Utils.hs+3
default.nix+11−6
@@ -68,6 +68,7 @@ let
6868 obelisk-cliapp = self.callCabal2nix "obelisk-cliapp" (cleanSource ./lib/cliapp) {};
6969 obelisk-command = haskellLib.overrideCabal (self.callCabal2nix "obelisk-command" (cleanSource ./lib/command) {}) {
7070 librarySystemDepends = [
71+ pkgs.jre
7172 pkgs.nix
7273 (haskellLib.justStaticExecutables self.ghcid)
7374 ];
@@ -173,10 +174,14 @@ in rec {
173174 '';
174175
175176 serverModules = {
176− mkBaseEc2 = { hostName, routeHost, enableHttps, adminEmail, ... }: {...}: {
177+ mkBaseEc2 = { nixosPkgs, ... }: {...}: {
177178 imports = [
178− (pkgs.path + /nixos/modules/virtualisation/amazon-image.nix)
179+ (nixosPkgs.path + /nixos/modules/virtualisation/amazon-image.nix)
179180 ];
181+ ec2.hvm = true;
182+ };
183+
184+ mkDefaultNetworking = { adminEmail, enableHttps, hostName, routeHost, ... }: {...}: {
180185 networking = {
181186 inherit hostName;
182187 firewall.allowedTCPPorts = if enableHttps then [ 80 443 ] else [ 80 ];
@@ -184,7 +189,6 @@ in rec {
184189 security.acme.certs = if enableHttps then {
185190 "${routeHost}".email = adminEmail;
186191 } else {};
187− ec2.hvm = true;
188192 };
189193
190194 mkObeliskApp =
@@ -251,14 +255,15 @@ in rec {
251255 echo ${version} > $out/version
252256 '';
253257
254− server = { exe, hostName, adminEmail, routeHost, enableHttps, version }@args:
258+ server = { exe, hostName, adminEmail, routeHost, enableHttps, version, module ? serverModules.mkBaseEc2 }@args:
255259 let
256260 nixos = import (pkgs.path + /nixos);
257261 in nixos {
258262 system = "x86_64-linux";
259263 configuration = {
260264 imports = [
261− (serverModules.mkBaseEc2 args)
265+ (module { inherit exe hostName adminEmail routeHost enableHttps version; nixosPkgs = pkgs; })
266+ (serverModules.mkDefaultNetworking args)
262267 (serverModules.mkObeliskApp args)
263268 ];
264269 };
@@ -385,7 +390,7 @@ in rec {
385390 linuxExeConfigurable = linuxExe;
386391 linuxExe = linuxExe dummyVersion;
387392 exe = serverOn mainProjectOut dummyVersion;
388− server = args@{ hostName, adminEmail, routeHost, enableHttps, version }:
393+ server = args@{ hostName, adminEmail, routeHost, enableHttps, version, module ? serverModules.mkBaseEc2 }:
389394 server (args // { exe = linuxExe version; });
390395 obelisk = import (base' + "/.obelisk/impl") {};
391396 };
lib/command/src/Obelisk/Command.hs+2−2
@@ -155,8 +155,8 @@ deployCommand cfg = hsubparser $ mconcat
155155
156156deployInitOpts :: Parser DeployInitOpts
157157deployInitOpts = DeployInitOpts
158− <$> strArgument (action "directory" <> metavar "DEPLOYDIR" <> help "Path to a directory that it will create")
159− <*> strOption (long "ssh-key" <> action "file" <> metavar "SSHKEY" <> help "Path to an ssh key that it will symlink to")
158+ <$> strArgument (action "directory" <> metavar "DEPLOYDIR" <> help "Path to a directory where the deployment repository will be initialized")
159+ <*> strOption (long "ssh-key" <> action "file" <> metavar "SSHKEY" <> help "Path to an SSH key that will be *copied* to the deployment repository")
160160 <*> some (strOption (long "hostname" <> metavar "HOSTNAME" <> help "hostname of the deployment target"))
161161 <*> strOption (long "route" <> metavar "PUBLICROUTE" <> help "Publicly accessible URL of your app")
162162 <*> strOption (long "admin-email" <> metavar "ADMINEMAIL" <> help "Email address where administrative alerts will be sent")
lib/command/src/Obelisk/Command/Deploy.hs+36−26
@@ -48,6 +48,7 @@ deployInit
4848 -> Bool -- ^ enable https
4949 -> m ()
5050deployInit thunkPtr deployDir sshKeyPath hostnames route adminEmail enableHttps = do
51+ liftIO $ createDirectoryIfMissing True deployDir
5152 localKey <- withSpinner ("Preparing " <> T.pack deployDir) $ do
5253 localKey <- liftIO (doesFileExist sshKeyPath) >>= \case
5354 False -> failWith $ T.pack $ "ob deploy init: file does not exist: " <> sshKeyPath
@@ -74,22 +75,30 @@ deployInit thunkPtr deployDir sshKeyPath hostnames route adminEmail enableHttps
7475 , deployDir </> "config" </> "common"
7576 , deployDir </> "config" </> "frontend"
7677 ]
78+
79+ let srcDir = deployDir </> "src"
80+ withSpinner ("Creating source thunk (" <> T.pack (makeRelative deployDir srcDir) <> ")") $ liftIO $ do
81+ createThunk srcDir thunkPtr
82+ setupObeliskImpl deployDir
83+
7784 withSpinner "Writing deployment configuration" $ do
7885 writeDeployConfig deployDir "backend_hosts" $ unlines hostnames
7986 writeDeployConfig deployDir "enable_https" $ show enableHttps
8087 writeDeployConfig deployDir "admin_email" adminEmail
8188 writeDeployConfig deployDir ("config" </> "common" </> "route") route
82− withSpinner "Creating source thunk (./src)" $ liftIO $ do
83− createThunk (deployDir </> "src") thunkPtr
84− setupObeliskImpl deployDir
89+ writeDeployConfig deployDir "module.nix" $
90+ "(import " <> toNixPath (makeRelative deployDir srcDir) <> " {}).obelisk.serverModules.mkBaseEc2"
91+
8592 withSpinner ("Initializing git repository (" <> T.pack deployDir <> ")") $
8693 initGit deployDir
8794
8895setupObeliskImpl :: FilePath -> IO ()
8996setupObeliskImpl deployDir = do
90− let implDir = toImplDir deployDir
97+ let
98+ implDir = toImplDir deployDir
99+ goBackUp = foldr (</>) "" $ (".." <$) $ splitPath $ makeRelative deployDir implDir
91100 createDirectoryIfMissing True implDir
92− writeFile (implDir </> "default.nix") "(import ../../src {}).obelisk"
101+ writeFile (implDir </> "default.nix") $ "(import " <> toNixPath (goBackUp </> "src") <> " {}).obelisk"
93102
94103deployPush :: MonadObelisk m => FilePath -> m [String] -> m ()
95104deployPush deployPath getNixBuilders = do
@@ -108,6 +117,8 @@ deployPush deployPath getNixBuilders = do
108117 Left err -> failWith $ "ob deploy push: couldn't read src thunk: " <> T.pack (show err)
109118 let version = show . _thunkRev_commit $ _thunkPtr_rev thunkPtr
110119 builders <- getNixBuilders
120+ let moduleFile = deployPath </> "module.nix"
121+ moduleFileExists <- liftIO $ doesFileExist moduleFile
111122 buildOutputByHost <- ifor (Map.fromSet (const ()) hosts) $ \host () -> do
112123 --TODO: What does it mean if this returns more or less than 1 line of output?
113124 [result] <- fmap lines $ nixCmd $ NixCmd_Build $ def
@@ -117,13 +128,13 @@ deployPush deployPath getNixBuilders = do
117128 , _target_expr = Nothing
118129 }
119130 & nixBuildConfig_outLink .~ OutLink_None
120− & nixCmdConfig_args .~
131+ & nixCmdConfig_args .~ (
121132 [ strArg "hostName" host
122133 , strArg "adminEmail" adminEmail
123134 , strArg "routeHost" routeHost
124135 , strArg "version" version
125136 , boolArg "enableHttps" enableHttps
126− ]
137+ ] <> [rawArg "module" ("import " <> toNixPath moduleFile) | moduleFileExists ])
127138 & nixCmdConfig_builders .~ builders
128139 pure result
129140 let knownHostsPath = deployPath </> "backend_known_hosts"
@@ -207,12 +218,14 @@ deployMobile platform mobileArgs = withProjectRoot "." $ \root -> do
207218 keytoolConfContents <- liftIO $ BSL.readFile keytoolConfPath
208219 keyArgs <- case eitherDecode keytoolConfContents :: Either String KeytoolConfig of
209220 Left err -> failWith $ T.pack err
210− Right conf -> pure [ "--sign"
211− , "--store-file", _keytoolConfig_keystore conf
212− , "--store-password", _keytoolConfig_storepass conf
213− , "--key-alias", _keytoolConfig_alias conf
214− , "--key-password", _keytoolConfig_keypass conf]
215− let expr = unwords
221+ Right conf -> pure
222+ [ "--sign"
223+ , "--store-file", _keytoolConfig_keystore conf
224+ , "--store-password", _keytoolConfig_storepass conf
225+ , "--key-alias", _keytoolConfig_alias conf
226+ , "--key-password", _keytoolConfig_keypass conf
227+ ]
228+ let expr = mconcat
216229 [ "with (import ", toNixPath srcDir, " {});"
217230 , "android.frontend.override (drv: {"
218231 , "isRelease = true;"
@@ -264,19 +277,16 @@ instance FromJSON KeytoolConfig
264277instance ToJSON KeytoolConfig
265278
266279createKeystore :: MonadObelisk m => FilePath -> KeytoolConfig -> m ()
267−createKeystore root config = do
268− let expr = "with (import " <> toImplDir root <> ").reflex-platform.nixpkgs; pkgs.mkShell { buildInputs = [ pkgs.jdk ]; }"
269− callProcessAndLogOutput (Notice,Notice) $ setCwd (Just root) $ proc "nix-shell" ["-E" , expr, "--run" , keytoolCmd]
270− where
271− keytoolCmd = processToShellString "keytool"
272− [ "-genkeypair", "-noprompt"
273− , "-keystore", _keytoolConfig_keystore config
274− , "-keyalg", "RSA", "-keysize", "2048"
275− , "-validity", "1000000"
276− , "-storepass", _keytoolConfig_storepass config
277− , "-alias", _keytoolConfig_alias config
278− , "-keypass", _keytoolConfig_keypass config
279− ]
280+createKeystore root config =
281+ callProcessAndLogOutput (Notice, Notice) $ setCwd (Just root) $ proc jreKeyToolPath
282+ [ "-genkeypair", "-noprompt"
283+ , "-keystore", _keytoolConfig_keystore config
284+ , "-keyalg", "RSA", "-keysize", "2048"
285+ , "-validity", "1000000"
286+ , "-storepass", _keytoolConfig_storepass config
287+ , "-alias", _keytoolConfig_alias config
288+ , "-keypass", _keytoolConfig_keypass config
289+ ]
280290
281291-- | Simplified deployment configuration mechanism. At one point we may revisit this.
282292writeDeployConfig :: MonadObelisk m => FilePath -> FilePath -> String -> m ()
lib/command/src/Obelisk/Command/Utils.hs+3
@@ -44,6 +44,9 @@ nixExePath = $(staticWhich "nix")
4444nixBuildExePath :: FilePath
4545nixBuildExePath = $(staticWhich "nix-build")
4646
47+jreKeyToolPath :: FilePath
48+jreKeyToolPath = $(staticWhich "keytool")
49+
4750-- Check whether the working directory is clean
4851checkGitCleanStatus :: MonadObelisk m => FilePath -> Bool -> m Bool
4952checkGitCleanStatus repo withIgnored = do