@@ -44,7 +44,8 @@ data AppState = AppState
4444 , creation_command :: Command
4545 , update_command :: Command
4646 , deletion_command :: Command
47− , checking_command :: Command }
47+ , checking_command :: Command
48+ , cleanup_command :: Command }
4849
4950data DeploymentException
5051 = DeploymentFailed Int
@@ -69,6 +70,7 @@ runDMS = do
6970 update_cmd <- coerce . pack <$> getEnvOrDie "UPDATE_COMMAND"
7071 deletion_cmd <- coerce . pack <$> getEnvOrDie "DELETION_COMMAND"
7172 checking_cmd <- coerce . pack <$> getEnvOrDie "CHECKING_COMMAND"
73+ cleanup_cmd <- coerce . pack <$> getEnvOrDie "CLEANUP_COMMAND"
7274 pgPool <- initConnectionPool
7375 (unDBConnectionString $ dmsDB opts) (unDBPoolSize $ dmsDBPoolSize opts)
7476 let
@@ -83,6 +85,7 @@ runDMS = do
8385 update_cmd
8486 deletion_cmd
8587 checking_cmd
88+ cleanup_cmd
8689 serverPort = dmsPort opts
8790 uiServerPort = unServerPort $ dmsUIPort opts
8891 tlsOpts =
@@ -106,22 +109,22 @@ app s = serve api $ hoistServer api (nt s) server
106109server :: ServerT API AppM
107110server =
108111 (listH :<|> createH :<|> getH :<|> editH
109− :<|> destroyH :<|> updateH :<|> infoH :<|> statusH) :<|> pingH
112+ :<|> deleteH :<|> updateH :<|> infoH :<|> statusH :<|> cleanupH) :<|> pingH
110113
111114listH :: AppM [DeploymentFullInfo]
112115listH = do
113116 AppState {pool = p, logger = l, base_domain = d} <- ask
114117
115118 retrieved <- liftIO $ withResource p $ \conn -> query_ conn q
116− deployments <- liftIO $ for retrieved $ \(n, t, e, ct, ut) -> do
119+ deployments <- liftIO $ for retrieved $ \(n, t, e, a, ct, ut) -> do
117120 es <- parseEnvs (lines e)
118− pure $ DeploymentFullInfo (Deployment n t es) ct ut (depUrls d n)
121+ pure $ DeploymentFullInfo (Deployment n t es) a ct ut (depUrls d n)
119122
120123 liftIO . logInfo l $ "get deployments: " <> (pack . show $ deployments)
121124 return deployments
122125 where
123126 q =
124− "SELECT name, tag, envs, extract(epoch from created_at)::int, \
127+ "SELECT name, tag, envs, archived, extract(epoch from created_at)::int, \
125128 \extract(epoch from updated_at)::int \
126129 \FROM deployments ORDER BY name"
127130 depUrls domain dName =
@@ -160,7 +163,7 @@ createH dep = do
160163 log $ "call " <> unwords (cmd : args)
161164 ec <- withProcessWait (proc (unpack cmd) (unpack <$> args)) waitProcess
162165 log $ "deployment created, deployment: " <> (pack . show $ dep)
163− createDeploymentLog pgPool dep "create" ec
166+ createDeploymentLog pgPool dep "create" ec $ ArchivedFlag False
164167 handleExitCode ec
165168 pure NoContent
166169
@@ -193,6 +196,7 @@ selectDeploymentLogs p dName = do
193196selectDeployment :: PgPool -> DeploymentName -> IO Deployment
194197selectDeployment p n = selectDeployments p n >>= \case
195198 [d] -> pure d
199+ [] -> error "deployment not found"
196200 _ -> error "more than one deployment found in the database"
197201
198202selectDeployments :: PgPool -> DeploymentName -> IO [Deployment]
@@ -229,7 +233,7 @@ editH dName dEnvs = do
229233 $ "deployment edited, name: " <> coerce dName
230234 <> ", envs: " <> formatEnvPairs dEnvs
231235 let dep = Deployment dName dTag dEnvs
232− createDeploymentLog pgPool dep "edit" ec
236+ createDeploymentLog pgPool dep "edit" ec $ ArchivedFlag False
233237 handleExitCode ec
234238 return ()
235239 _ ->
@@ -246,8 +250,8 @@ editH dName dEnvs = do
246250 -- FIXME: make EnvPairs a newtype and give it ToField instance
247251 (formatEnvPairs dEnvs, dName)
248252
249−destroyH :: DeploymentName -> AppM NoContent
250−destroyH dName = do
253+deleteH :: DeploymentName -> AppM NoContent
254+deleteH dName = do
251255 st <- ask
252256 let
253257 log = logInfo (logger st)
@@ -259,24 +263,23 @@ destroyH dName = do
259263 ]
260264 cmd = coerce $ deletion_command st
261265 liftIO $ do
266+ dep <- selectDeployment pgPool dName
262267 log $ "call " <> unwords (cmd : args)
263268 ec <- withProcessWait (proc (unpack cmd) (unpack <$> args)) waitProcess
264− void $ deleteDeploymentLogs pgPool dName
265− void $ deleteDeployment pgPool dName
266− log $ "deployment destroyed, name: " <> coerce dName
269+ void $ archiveDeployment pgPool dName
270+ void $ createDeploymentLog pgPool dep "delete" ec $ ArchivedFlag True
271+ log $ "deployment deleted, name: " <> coerce dName
267272 handleExitCode ec
268273 pure NoContent
269274
270−deleteDeploymentLogs :: PgPool -> DeploymentName -> IO Int64
271−deleteDeploymentLogs p n = withResource p $ \conn -> execute
272− conn
273− "DELETE FROM deployment_logs WHERE deployment_id in\
274− \ (SELECT id FROM deployments where name = ?)"
275− (Only n)
276−
277−deleteDeployment :: PgPool -> DeploymentName -> IO Int64
278−deleteDeployment p n = withResource p $ \conn ->
279− execute conn "DELETE FROM deployments WHERE name = ?" (Only n)
275+archiveDeployment :: PgPool -> DeploymentName -> IO Int64
276+archiveDeployment p dName = withResource p $ \conn -> do
277+ let
278+ q =
279+ "UPDATE deployments \
280+ \SET archived = 't', archived_at = now() \
281+ \WHERE name = ?"
282+ execute conn q (Only dName)
280283
281284updateH :: DeploymentName -> DeploymentUpdate -> AppM NoContent
282285updateH dName DeploymentUpdate { newTag = dTag, newEnvs = nEnvs } = do
@@ -304,7 +307,11 @@ updateH dName DeploymentUpdate { newTag = dTag, newEnvs = nEnvs } = do
304307 ec <- withProcessWait (proc (unpack cmd) (unpack <$> args)) waitProcess
305308 log $ "deployment updated, name: "
306309 <> coerce dName <> ", tag: " <> coerce dTag
307− createDeploymentLog pgPool (Deployment dName dTag envPairs) "update" ec
310+ void $ do
311+ let
312+ dep = Deployment dName dTag envPairs
313+ arch = ArchivedFlag False
314+ createDeploymentLog pgPool dep "update" ec arch
308315 handleExitCode ec
309316 return ()
310317 _ ->
@@ -355,6 +362,38 @@ statusH dName = do
355362 ExitSuccess -> Ok
356363 _ -> Error
357364
365+cleanupH :: DeploymentName -> AppM NoContent
366+cleanupH dName = do
367+ st <- ask
368+ let
369+ log = logInfo (logger st)
370+ pgPool = pool st
371+ args =
372+ [ "--project-name", coerce $ project_name st
373+ , "--namespace", coerce $ namespace st
374+ , "--name", coerce dName
375+ ]
376+ cmd = coerce $ cleanup_command st
377+ liftIO $ do
378+ log $ "call " <> unwords (cmd : args)
379+ ec <- withProcessWait (proc (unpack cmd) (unpack <$> args)) waitProcess
380+ void $ deleteDeploymentLogs pgPool dName
381+ void $ deleteDeployment pgPool dName
382+ log $ "deployment destroyed, name: " <> coerce dName
383+ handleExitCode ec
384+ pure NoContent
385+
386+deleteDeploymentLogs :: PgPool -> DeploymentName -> IO Int64
387+deleteDeploymentLogs p n = withResource p $ \conn -> execute
388+ conn
389+ "DELETE FROM deployment_logs WHERE deployment_id in\
390+ \ (SELECT id FROM deployments where name = ?)"
391+ (Only n)
392+
393+deleteDeployment :: PgPool -> DeploymentName -> IO Int64
394+deleteDeployment p n = withResource p $ \conn ->
395+ execute conn "DELETE FROM deployments WHERE name = ?" (Only n)
396+
358397waitProcess :: (Show o, Show e) => Process i o e -> IO ExitCode
359398waitProcess p = do
360399 print . getStdout $ p
@@ -365,21 +404,28 @@ handleExitCode :: ExitCode -> IO ()
365404handleExitCode ExitSuccess = return ()
366405handleExitCode (ExitFailure c) = throwIO $ DeploymentFailed c
367406
368−createDeploymentLog :: PgPool -> Deployment -> Action -> ExitCode -> IO ()
369−createDeploymentLog pgPool (Deployment n t e) a ec = do
407+createDeploymentLog
408+ :: PgPool
409+ -> Deployment
410+ -> Action
411+ -> ExitCode
412+ -> ArchivedFlag
413+ -> IO ()
414+createDeploymentLog pgPool (Deployment dName dTag dEnvs) act ec arch = do
370415 let
371416 exitCode' = case ec of
372417 ExitSuccess -> 0
373418 ExitFailure err -> err
419+ arch' = unArchivedFlag arch
374420 q =
375421 "INSERT INTO deployment_logs \
376− \(deployment_id, action, tag, envs, exit_code) (\
377− \SELECT id, ?, ?, ?, ? \
422+ \(deployment_id, action, tag, envs, exit_code, archived) (\
423+ \SELECT id, ?, ?, ?, ?, ? \
378424 \FROM deployments \
379425 \WHERE name = ? \
380426 \)"
381427 void $ withResource pgPool $ \conn ->
382− execute conn q (a, t, formatEnvPairs e, exitCode', n)
428+ execute conn q (act, dTag, formatEnvPairs dEnvs, exitCode', arch', dName)
383429
384430logInfo :: TimedFastLogger -> Text -> IO ()
385431logInfo l = logWithSeverity l "INFO"