1
1
package org .broadinstitute .dsde .workbench .leonardo .monitor
2
2
3
3
import java .time .Instant
4
+ import java .time .temporal .ChronoUnit
4
5
5
6
import akka .actor .Status .Failure
6
- import akka .actor .{Actor , ActorSystem , Props }
7
+ import akka .actor .{Actor , Props }
7
8
import akka .pattern .pipe
8
9
import cats .data .OptionT
9
10
import cats .implicits ._
10
11
import com .google .api .client .googleapis .json .GoogleJsonResponseException
11
12
import com .typesafe .scalalogging .LazyLogging
12
13
import io .grpc .Status .Code
13
14
import org .broadinstitute .dsde .workbench .google .{GoogleIamDAO , GoogleStorageDAO }
14
- import org .broadinstitute .dsde .workbench .leonardo .config .{DataprocConfig , MonitorConfig }
15
+ import org .broadinstitute .dsde .workbench .leonardo .config .{DataprocConfig , MonitorConfig , ClusterBucketConfig }
15
16
import org .broadinstitute .dsde .workbench .leonardo .dao .JupyterDAO
16
17
import org .broadinstitute .dsde .workbench .leonardo .dao .google .{GoogleComputeDAO , GoogleDataprocDAO }
17
18
import org .broadinstitute .dsde .workbench .leonardo .db .DbReference
@@ -20,6 +21,7 @@ import org.broadinstitute.dsde.workbench.leonardo.model.google.ClusterStatus._
20
21
import org .broadinstitute .dsde .workbench .leonardo .model .google .{ClusterStatus , IP , _ }
21
22
import org .broadinstitute .dsde .workbench .leonardo .monitor .ClusterMonitorActor ._
22
23
import org .broadinstitute .dsde .workbench .leonardo .monitor .ClusterMonitorSupervisor .{ClusterDeleted , ClusterSupervisorMessage , RemoveFromList }
24
+ import org .broadinstitute .dsde .workbench .model .google .GcsLifecycleTypes
23
25
import org .broadinstitute .dsde .workbench .util .{Retry , addJitter }
24
26
import slick .dbio .DBIOAction
25
27
@@ -31,8 +33,8 @@ object ClusterMonitorActor {
31
33
/**
32
34
* Creates a Props object used for creating a {{{ClusterMonitorActor}}}.
33
35
*/
34
- def props (cluster : Cluster , monitorConfig : MonitorConfig , dataprocConfig : DataprocConfig , gdDAO : GoogleDataprocDAO , googleComputeDAO : GoogleComputeDAO , googleIamDAO : GoogleIamDAO , googleStorageDAO : GoogleStorageDAO , dbRef : DbReference , authProvider : LeoAuthProvider , jupyterProxyDAO : JupyterDAO ): Props =
35
- Props (new ClusterMonitorActor (cluster, monitorConfig, dataprocConfig, gdDAO, googleComputeDAO, googleIamDAO, googleStorageDAO, dbRef, authProvider, jupyterProxyDAO))
36
+ def props (cluster : Cluster , monitorConfig : MonitorConfig , dataprocConfig : DataprocConfig , clusterBucketConfig : ClusterBucketConfig , gdDAO : GoogleDataprocDAO , googleComputeDAO : GoogleComputeDAO , googleIamDAO : GoogleIamDAO , googleStorageDAO : GoogleStorageDAO , dbRef : DbReference , authProvider : LeoAuthProvider , jupyterProxyDAO : JupyterDAO ): Props =
37
+ Props (new ClusterMonitorActor (cluster, monitorConfig, dataprocConfig, clusterBucketConfig, gdDAO, googleComputeDAO, googleIamDAO, googleStorageDAO, dbRef, authProvider, jupyterProxyDAO))
36
38
37
39
// ClusterMonitorActor messages:
38
40
@@ -58,6 +60,7 @@ object ClusterMonitorActor {
58
60
class ClusterMonitorActor (val cluster : Cluster ,
59
61
val monitorConfig : MonitorConfig ,
60
62
val dataprocConfig : DataprocConfig ,
63
+ val clusterBucketConfig : ClusterBucketConfig ,
61
64
val gdDAO : GoogleDataprocDAO ,
62
65
val googleComputeDAO : GoogleComputeDAO ,
63
66
val googleIamDAO : GoogleIamDAO ,
@@ -230,6 +233,9 @@ class ClusterMonitorActor(val cluster: Cluster,
230
233
// delete the init bucket so we don't continue to accrue costs after cluster is deleted
231
234
_ <- deleteInitBucket
232
235
236
+ // set the staging bucket to be deleted in ten days so that logs are still accessible until then
237
+ _ <- setStagingBucketLifecycle
238
+
233
239
// delete instances in the DB
234
240
_ <- persistInstances(Set .empty)
235
241
@@ -395,14 +401,28 @@ class ClusterMonitorActor(val cluster: Cluster,
395
401
dbRef.inTransaction { dataAccess =>
396
402
dataAccess.clusterQuery.getInitBucket(cluster.googleProject, cluster.clusterName)
397
403
} flatMap {
398
- case None => Future .successful( logger.warn(s " Could not lookup bucket for cluster ${cluster.projectNameString}: cluster not in db " ) )
404
+ case None => Future .successful( logger.warn(s " Could not lookup init bucket for cluster ${cluster.projectNameString}: cluster not in db " ) )
399
405
case Some (bucketPath) =>
400
406
googleStorageDAO.deleteBucket(bucketPath.bucketName, recurse = true ) map { _ =>
401
407
logger.debug(s " Deleted init bucket $bucketPath for cluster ${cluster.googleProject}/ ${cluster.clusterName}" )
402
408
}
403
409
}
404
410
}
405
411
412
+ private def setStagingBucketLifecycle : Future [Unit ] = {
413
+ // Get the staging bucket path for this cluster, then set the age for it to be deleted the specified number of days after the deletion of the cluster.
414
+ dbRef.inTransaction { dataAccess =>
415
+ dataAccess.clusterQuery.getStagingBucket(cluster.googleProject, cluster.clusterName)
416
+ } flatMap {
417
+ case None => Future .successful( logger.warn(s " Could not lookup staging bucket for cluster ${cluster.projectNameString}: cluster not in db " ) )
418
+ case Some (bucketPath) =>
419
+ val ageToDelete = cluster.auditInfo.createdDate.until(Instant .now(), ChronoUnit .DAYS ).toInt + clusterBucketConfig.stagingBucketExpiration.toDays.toInt
420
+ googleStorageDAO.setBucketLifecycle(bucketPath.bucketName, ageToDelete, GcsLifecycleTypes .Delete ) map { _ =>
421
+ logger.debug(s " Set staging bucket $bucketPath for cluster ${cluster.googleProject}/ ${cluster.clusterName} to be deleted in ${ageToDelete} days. " )
422
+ }
423
+ }
424
+ }
425
+
406
426
private def removeCredentialsFromMetadata : Future [Unit ] = {
407
427
cluster.serviceAccountInfo.notebookServiceAccount match {
408
428
// No notebook service account: don't remove creds from metadata! We need them.
0 commit comments