git.iko.soy/typeable/octopod
on master help sign in
improve error handling
commite519ca1858f221b38dbc2a6394bf56be86e3332d authorAndrei Orlov <aaorlov1@gmail.com> dateThu 11 Jun 2020, 15:54 (6 years ago) parent246a3cd
9 files changed+78−39
default.nix+10−8 dm.cabal+4 src/DMC.hs+8−4 src/DMS.hs+26−23 utils/b2b-utils/src/bin/cleanup.rs+7−1 utils/b2b-utils/src/bin/create.rs+8−1 utils/b2b-utils/src/bin/delete.rs+7−1 utils/b2b-utils/src/bin/update.rs+7−1 utils/b2b-utils/src/lib.rs+1
default.nix+10−8
@@ -3,8 +3,9 @@
33, filepath, generic-lens, http-api-data, http-client
44, http-client-tls, lens, mtl, network-uri, optparse-generic
55, postgresql-simple, resource-pool, servant, servant-client
6−, servant-server, stdenv, temporary, text, tls, transformers
7−, typed-process, warp, warp-tls, x509, x509-store, x509-validation
6+, servant-client-core, servant-server, stdenv, temporary, text, tls
7+, transformers, typed-process, warp, warp-tls, x509, x509-store
8+, x509-validation
89}:
910mkDerivation {
1011 pname = "dm";
@@ -17,23 +18,24 @@ mkDerivation {
1718 deriving-aeson directory fast-logger filepath generic-lens
1819 http-api-data http-client http-client-tls lens mtl network-uri
1920 optparse-generic postgresql-simple resource-pool servant
20− servant-client servant-server temporary text tls transformers
21− typed-process warp warp-tls x509 x509-store x509-validation
21+ servant-client servant-client-core servant-server temporary text
22+ tls transformers typed-process warp warp-tls x509 x509-store
23+ x509-validation
2224 ];
2325 executableHaskellDepends = [
2426 aeson async base bytestring chronos connection data-default-class
2527 directory fast-logger filepath http-client http-client-tls mtl
2628 network-uri optparse-generic postgresql-simple resource-pool
27− servant servant-client servant-server temporary text tls
28− transformers typed-process warp warp-tls x509 x509-store
29+ servant servant-client servant-client-core servant-server temporary
30+ text tls transformers typed-process warp warp-tls x509 x509-store
2931 x509-validation
3032 ];
3133 testHaskellDepends = [
3234 aeson async base bytestring chronos connection data-default-class
3335 directory fast-logger filepath http-client http-client-tls mtl
3436 network-uri optparse-generic postgresql-simple resource-pool
35− servant servant-client servant-server temporary text tls
36− transformers typed-process warp warp-tls x509 x509-store
37+ servant servant-client servant-client-core servant-server temporary
38+ text tls transformers typed-process warp warp-tls x509 x509-store
3739 x509-validation
3840 ];
3941 homepage = "https://github.com/https://github.com/Aviora/dm#readme";
dm.cabal+4
@@ -73,6 +73,7 @@ library
7373 , resource-pool
7474 , servant
7575 , servant-client
76+ , servant-client-core
7677 , servant-server
7778 , temporary
7879 , text
@@ -116,6 +117,7 @@ executable dmc-exe
116117 , resource-pool
117118 , servant
118119 , servant-client
120+ , servant-client-core
119121 , servant-server
120122 , temporary
121123 , text
@@ -158,6 +160,7 @@ executable dms-exe
158160 , resource-pool
159161 , servant
160162 , servant-client
163+ , servant-client-core
161164 , servant-server
162165 , temporary
163166 , text
@@ -200,6 +203,7 @@ test-suite dm-test
200203 , resource-pool
201204 , servant
202205 , servant-client
206+ , servant-client-core
203207 , servant-server
204208 , temporary
205209 , text
src/DMC.hs+8−4
@@ -18,8 +18,10 @@ import Network.URI
1818import Prelude as P
1919import Servant.API
2020import Servant.Client
21− (ClientError, BaseUrl(..), ClientEnv, ClientM, Scheme(..)
21+ (BaseUrl(..), ClientError, ClientEnv, ClientM, Scheme(..)
2222 , runClientM, client, mkClientEnv)
23+import Servant.Client.Core
24+ (ClientError(FailureResponse), ResponseF(..))
2325import System.Environment (lookupEnv)
2426import System.IO
2527import System.IO.Temp
@@ -203,9 +205,11 @@ cleanArchiveH :: ClientM NoContent
203205 :<|> _pingH :<|> cleanArchiveH = client (Proxy @API)
204206
205207handleResponse :: (a -> IO ()) -> Either ClientError a -> IO ()
206−handleResponse f (Right result) = f result
207−handleResponse _ (Left err) =
208− T.putStrLn $ "command failed, reason: " <> T.pack (show err)
208+handleResponse f (Right result) = f result
209+handleResponse _ (Left (FailureResponse _req res)) =
210+ T.putStrLn $ "error: " <> T.pack (show $ responseBody res)
211+handleResponse _ (Left err) =
212+ T.putStrLn $ "command failed due to unknown reason: " <> T.pack (show err)
209213
210214printInfo :: DeploymentInfo -> IO ()
211215printInfo (DeploymentInfo (Deployment dName dTag envPairs) dLogs) = do
src/DMS.hs+26−23
@@ -3,7 +3,7 @@ module DMS (runDMS) where
33
44import Control.Applicative
55import Control.Concurrent.Async (race_)
6−import Control.Exception (throwIO, Exception)
6+import Control.Exception (throwIO, try, Exception)
77import Control.Monad
88import Control.Monad.IO.Class
99import Control.Monad.Trans.Reader (ReaderT, ask, runReaderT)
@@ -72,7 +72,7 @@ runDMS = do
7272 projName <- coerce . pack <$> getEnvOrDie "PROJECT_NAME"
7373 domain <- coerce . pack <$> getEnvOrDie "BASE_DOMAIN"
7474 ns <- coerce . pack <$> getEnvOrDie "NAMESPACE"
75− archRetention <- ArchiveRetention . read <$> getEnvOrDie "ARCHIVE_RETENTION"
75+ archRetention <- coerce . read @Int <$> getEnvOrDie "ARCHIVE_RETENTION"
7676 creationCmd <- coerce . pack <$> getEnvOrDie "CREATION_COMMAND"
7777 updateCmd <- coerce . pack <$> getEnvOrDie "UPDATE_COMMAND"
7878 deletionCmd <- coerce . pack <$> getEnvOrDie "DELETION_COMMAND"
@@ -155,7 +155,10 @@ createH dep = do
155155 "INSERT INTO deployments (name, tag, envs) VALUES (?, ?, ?)"
156156 -- FIXME: make EnvPairs a newtype and give it ToField instance
157157 (n, t, formatEnvPairs e)
158− void $ liftIO $ createDep pgPool dep
158+ res :: Either SqlError Int64 <- liftIO . try $ createDep pgPool dep
159+ case res of
160+ Right _ -> pure ()
161+ Left _ -> throwError err400 { errBody = "deployment already exists" }
159162 ec <- createDeployment dep st
160163 void $ liftIO $ do
161164 createDeploymentLog pgPool dep "create" ec $ ArchivedFlag False
@@ -185,8 +188,8 @@ createDeployment dep st = do
185188getH :: DeploymentName -> AppM Deployment
186189getH dName = do
187190 st <- ask
191+ dep <- selectDeployment (pool st) dName AllDeployments
188192 liftIO $ do
189− dep <- selectDeployment (pool st) dName AllDeployments
190193 logInfo (logger st) $ "get deployment: " <> (pack . show $ dep)
191194 return dep
192195
@@ -212,28 +215,25 @@ selectDeployment
212215 :: PgPool
213216 -> DeploymentName
214217 -> DeploymentListType
215− -> IO Deployment
216−selectDeployment p n t = selectDeployments p n t >>= \case
217− [d] -> pure d
218− [] -> error "deployment not found"
219− _ -> error "more than one deployment found in the database"
220−
221−selectDeployments
222− :: PgPool
223− -> DeploymentName
224− -> DeploymentListType
225− -> IO [Deployment]
226−selectDeployments p dName lType = do
218+ -> AppM Deployment
219+selectDeployment p dName lType = do
227220 let
228221 q AllDeployments =
229− "SELECT name, tag, envs FROM deployments WHERE name = ?"
222+ "SELECT name, tag, envs FROM deployments \
223+ \WHERE name = ?"
230224 q ArchivedOnlyDeployments =
231225 "SELECT name, tag, envs FROM deployments \
232226 \WHERE name = ? AND archived = 't'"
233227
234− retrieved <- withResource p $ \conn ->
235− query conn (q lType) (Only dName)
236− for retrieved $ \(n, t, e) -> Deployment n t <$> parseEnvs (lines e)
228+ deps <- liftIO $ do
229+ retrieved <- withResource p $ \conn ->
230+ query conn (q lType) (Only dName)
231+ for retrieved $ \(n, t, e) -> Deployment n t <$> parseEnvs (lines e)
232+ case deps of
233+ [dep] -> pure dep
234+ [] -> throwError err404 { errBody = "deployment not found" }
235+ _ -> throwError err406
236+ { errBody = "more than one deployment found in the database" }
237237
238238editH :: DeploymentName -> EnvPairs -> AppM NoContent
239239editH dName dEnvs = do
@@ -290,8 +290,8 @@ deleteH dName = do
290290 , "--name", coerce dName
291291 ]
292292 cmd = coerce $ deletionCommand st
293+ dep <- selectDeployment pgPool dName AllDeployments
293294 liftIO $ do
294− dep <- selectDeployment pgPool dName AllDeployments
295295 log $ "call " <> unwords (cmd : args)
296296 ec <- withProcessWait (proc (unpack cmd) (unpack <$> args)) waitProcess
297297 void $ archiveDeployment pgPool dName
@@ -366,8 +366,8 @@ infoH :: DeploymentName -> AppM [DeploymentInfo]
366366infoH dName = do
367367 st <- ask
368368 let pgPool = pool st
369+ dep <- selectDeployment pgPool dName AllDeployments
369370 liftIO $ do
370− dep <- selectDeployment pgPool dName AllDeployments
371371 depLogs <- selectDeploymentLogs pgPool dName
372372 let depInfo = DeploymentInfo dep $ reverse depLogs
373373 logInfo (logger st) $ "get deployment info: " <> (pack . show $ depInfo)
@@ -382,6 +382,9 @@ pingH = do
382382
383383statusH :: DeploymentName -> AppM DeploymentStatus
384384statusH dName = do
385+ st <- ask
386+ let pgPool = pool st
387+ void $ selectDeployment pgPool dName AllDeployments
385388 cmd <- checkingCommand <$> ask
386389 let args = [unpack . coerce $ dName]
387390 ec <- liftIO $ withProcessWait (proc (unpack $ coerce cmd) args) waitProcess
@@ -444,7 +447,7 @@ restoreH :: DeploymentName -> AppM NoContent
444447restoreH dName = do
445448 st <- ask
446449 let pgPool = pool st
447− dep <- liftIO $ selectDeployment pgPool dName ArchivedOnlyDeployments
450+ dep <- selectDeployment pgPool dName ArchivedOnlyDeployments
448451 ec <- createDeployment dep st
449452 void $ liftIO $ do
450453 let
utils/b2b-utils/src/bin/cleanup.rs+7−1
@@ -1,5 +1,5 @@
11use clap::{App, Arg};
2−use std::process::Command;
2+use std::process::{exit, Command};
33
44use b2b_utils::*;
55
@@ -40,13 +40,19 @@ fn main() -> std::io::Result<()> {
4040 .args(delete_pvcs_atrs(namespace, name))
4141 .output()
4242 .expect("delete PVCs");
43+ let success = output.status.success();
4344 print_command_result(output);
4445
4546 let output = Command::new("kubectl")
4647 .args(delete_cert_atrs(namespace, name))
4748 .output()
4849 .expect("delete certificates");
50+ let success2 = output.status.success();
4951 print_command_result(output);
5052
53+ if !(success && success2) {
54+ exit(1)
55+ }
56+
5157 Ok(())
5258}
utils/b2b-utils/src/bin/create.rs+8−1
@@ -2,7 +2,7 @@ use clap::{App, Arg};
22use std::convert::TryInto;
33use std::fs;
44use std::path::Path;
5−use std::process::Command;
5+use std::process::{exit, Command};
66
77use b2b_utils::*;
88
@@ -92,6 +92,7 @@ fn main() -> std::io::Result<()> {
9292 .current_dir(&work_dir)
9393 .output()
9494 .expect("clone repo");
95+ let success = output.status.success();
9596 print_command_result(output);
9697
9798 fs::copy(&b2b_heml, Path::new(&work_dir).join("b2b-helm"))?;
@@ -101,6 +102,7 @@ fn main() -> std::io::Result<()> {
101102 .current_dir(&work_dir)
102103 .output()
103104 .expect("create infra");
105+ let success2 = output.status.success();
104106 print_command_result(output);
105107
106108 let output = Command::new("b2b-helm")
@@ -108,7 +110,12 @@ fn main() -> std::io::Result<()> {
108110 .current_dir(&work_dir)
109111 .output()
110112 .expect("create app");
113+ let success3 = output.status.success();
111114 print_command_result(output);
112115
116+ if !(success && success2 && success3) {
117+ exit(1)
118+ }
119+
113120 Ok(())
114121}
utils/b2b-utils/src/bin/delete.rs+7−1
@@ -1,5 +1,5 @@
11use clap::{App, Arg};
2−use std::process::Command;
2+use std::process::{exit, Command};
33
44use b2b_utils::*;
55
@@ -40,13 +40,19 @@ fn main() -> std::io::Result<()> {
4040 .args(delete_app_atrs(name))
4141 .output()
4242 .expect("delete app");
43+ let success = output.status.success();
4344 print_command_result(output);
4445
4546 let output = Command::new("helm")
4647 .args(delete_infra_atrs(name))
4748 .output()
4849 .expect("delete infra");
50+ let success2 = output.status.success();
4951 print_command_result(output);
5052
53+ if !(success && success2) {
54+ exit(1)
55+ }
56+
5157 Ok(())
5258}
utils/b2b-utils/src/bin/update.rs+7−1
@@ -2,7 +2,7 @@ use clap::{App, Arg};
22use std::convert::TryInto;
33use std::fs;
44use std::path::Path;
5−use std::process::Command;
5+use std::process::{exit, Command};
66
77use b2b_utils::*;
88
@@ -92,6 +92,7 @@ fn main() -> std::io::Result<()> {
9292 .current_dir(&work_dir)
9393 .output()
9494 .expect("clone repo");
95+ let success = output.status.success();
9596 print_command_result(output);
9697
9798 fs::copy(&b2b_heml, Path::new(&work_dir).join("b2b-helm"))?;
@@ -101,7 +102,12 @@ fn main() -> std::io::Result<()> {
101102 .current_dir(&work_dir)
102103 .output()
103104 .expect("create app");
105+ let success2 = output.status.success();
104106 print_command_result(output);
105107
108+ if !(success && success2) {
109+ exit(1)
110+ }
111+
106112 Ok(())
107113}
utils/b2b-utils/src/lib.rs+1
@@ -56,6 +56,7 @@ pub fn whereis(cmd: &str) -> Option<String> {
5656}
5757
5858pub fn print_command_result(output: Output) {
59+ println!("status: {}", output.status);
5960 println!(
6061 "{}",
6162 String::from_utf8(output.stdout).expect("valid stdout")