Skip to content

Commit c6dff0e

Browse files
authored
AJ-1438: disable most entity APIs for Azure workspaces (#2641)
1 parent 672dd47 commit c6dff0e

File tree

8 files changed

+90
-46
lines changed

8 files changed

+90
-46
lines changed

core/src/main/scala/org/broadinstitute/dsde/rawls/entities/EntityManager.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.broadinstitute.dsde.rawls.entities
22

3+
import bio.terra.workspace.model.CloudPlatform
34
import org.broadinstitute.dsde.rawls.RawlsExceptionWithErrorReport
45
import org.broadinstitute.dsde.rawls.config.DataRepoEntityProviderConfig
56
import org.broadinstitute.dsde.rawls.dataaccess.datarepo.DataRepoDAO
@@ -9,7 +10,7 @@ import org.broadinstitute.dsde.rawls.entities.base.{EntityProvider, EntityProvid
910
import org.broadinstitute.dsde.rawls.entities.datarepo.{DataRepoEntityProvider, DataRepoEntityProviderBuilder}
1011
import org.broadinstitute.dsde.rawls.entities.exceptions.DataEntityException
1112
import org.broadinstitute.dsde.rawls.entities.local.{LocalEntityProvider, LocalEntityProviderBuilder}
12-
import org.broadinstitute.dsde.rawls.model.ErrorReport
13+
import org.broadinstitute.dsde.rawls.model.{ErrorReport, WorkspaceType}
1314

1415
import java.time.Duration
1516
import scala.concurrent.{ExecutionContext, Future}
@@ -43,6 +44,12 @@ class EntityManager(providerBuilders: Set[EntityProviderBuilder[_ <: EntityProvi
4344

4445
def resolveProvider(requestArguments: EntityRequestArguments): Try[EntityProvider] = {
4546

47+
if (!WorkspaceType.RawlsWorkspace.equals(requestArguments.workspace.workspaceType)) {
48+
throw new DataEntityException(
49+
s"This API is disabled for ${CloudPlatform.AZURE} workspaces. Contact support for alternatives."
50+
)
51+
}
52+
4653
// soon: look up the reference name to ensure it exists.
4754
// for now, this simplistic logic illustrates the approach: choose the right builder for the job.
4855
val targetTag = if (requestArguments.dataReference.isDefined) {

core/src/main/scala/org/broadinstitute/dsde/rawls/entities/EntityService.scala

Lines changed: 25 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -540,44 +540,31 @@ class EntityService(protected val ctx: RawlsRequestContext,
540540
}
541541
}
542542

543-
def copyEntities(entityCopyDef: EntityCopyDefinition,
544-
uri: Uri,
545-
linkExistingEntities: Boolean
546-
): Future[EntityCopyResponse] =
547-
getV2WorkspaceContextAndPermissions(entityCopyDef.destinationWorkspace,
548-
SamWorkspaceActions.write,
549-
Some(WorkspaceAttributeSpecs(all = false))
550-
) flatMap { destWorkspaceContext =>
551-
getV2WorkspaceContextAndPermissions(entityCopyDef.sourceWorkspace,
552-
SamWorkspaceActions.read,
553-
Some(WorkspaceAttributeSpecs(all = false))
554-
) flatMap { sourceWorkspaceContext =>
555-
dataSource.inTransaction { dataAccess =>
556-
for {
557-
sourceAD <- DBIO.from(
558-
samDAO.getResourceAuthDomain(SamResourceTypeNames.workspace, sourceWorkspaceContext.workspaceId, ctx)
559-
)
560-
destAD <- DBIO.from(
561-
samDAO.getResourceAuthDomain(SamResourceTypeNames.workspace, destWorkspaceContext.workspaceId, ctx)
562-
)
563-
result <- authDomainCheck(sourceAD.toSet, destAD.toSet) flatMap { _ =>
564-
val entityNames = entityCopyDef.entityNames
565-
val entityType = entityCopyDef.entityType
566-
val copyResults = traceDBIOWithParent("checkAndCopyEntities", ctx)(s1 =>
567-
dataAccess.entityQuery.checkAndCopyEntities(sourceWorkspaceContext,
568-
destWorkspaceContext,
569-
entityType,
570-
entityNames,
571-
linkExistingEntities,
572-
s1
573-
)
574-
)
575-
copyResults
576-
}
577-
} yield result
578-
}
579-
}
580-
}
543+
def copyEntities(entityCopyDef: EntityCopyDefinition, linkExistingEntities: Boolean): Future[EntityCopyResponse] =
544+
for {
545+
destWsCtx <- getV2WorkspaceContextAndPermissions(entityCopyDef.destinationWorkspace,
546+
SamWorkspaceActions.write,
547+
Some(WorkspaceAttributeSpecs(all = false))
548+
)
549+
sourceWsCtx <- getV2WorkspaceContextAndPermissions(entityCopyDef.sourceWorkspace,
550+
SamWorkspaceActions.read,
551+
Some(WorkspaceAttributeSpecs(all = false))
552+
)
553+
sourceAD <- samDAO.getResourceAuthDomain(SamResourceTypeNames.workspace, sourceWsCtx.workspaceId, ctx)
554+
destAD <- samDAO.getResourceAuthDomain(SamResourceTypeNames.workspace, destWsCtx.workspaceId, ctx)
555+
_ = authDomainCheck(sourceAD.toSet, destAD.toSet)
556+
entityRequestArguments = EntityRequestArguments(destWsCtx, ctx, None, None)
557+
entityProvider <- entityManager.resolveProviderFuture(entityRequestArguments)
558+
entityCopyResponse <- entityProvider
559+
.copyEntities(sourceWsCtx,
560+
destWsCtx,
561+
entityCopyDef.entityType,
562+
entityCopyDef.entityNames,
563+
linkExistingEntities,
564+
ctx
565+
)
566+
.recover(bigQueryRecover)
567+
} yield entityCopyResponse
581568

582569
def batchUpdateEntitiesInternal(workspaceName: WorkspaceName,
583570
entityUpdates: Seq[EntityUpdateDefinition],

core/src/main/scala/org/broadinstitute/dsde/rawls/entities/base/EntityProvider.scala

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ import org.broadinstitute.dsde.rawls.model.{
77
AttributeEntityReference,
88
AttributeValue,
99
Entity,
10+
EntityCopyDefinition,
11+
EntityCopyResponse,
1012
EntityQuery,
1113
EntityQueryResponse,
1214
EntityTypeMetadata,
1315
RawlsRequestContext,
14-
SubmissionValidationEntityInputs
16+
SubmissionValidationEntityInputs,
17+
Workspace
1518
}
1619

1720
import scala.concurrent.Future
@@ -70,4 +73,12 @@ trait EntityProvider {
7073
def batchUpdateEntities(entityUpdates: Seq[EntityUpdateDefinition]): Future[Traversable[Entity]]
7174

7275
def batchUpsertEntities(entityUpdates: Seq[EntityUpdateDefinition]): Future[Traversable[Entity]]
76+
77+
def copyEntities(sourceWorkspaceContext: Workspace,
78+
destWorkspaceContext: Workspace,
79+
entityType: String,
80+
entityNames: Seq[String],
81+
linkExistingEntities: Boolean,
82+
parentContext: RawlsRequestContext
83+
): Future[EntityCopyResponse]
7384
}

core/src/main/scala/org/broadinstitute/dsde/rawls/entities/datarepo/DataRepoEntityProvider.scala

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,16 @@ import org.broadinstitute.dsde.rawls.model.{
3838
AttributeValueList,
3939
AttributeValueRawJson,
4040
Entity,
41+
EntityCopyDefinition,
42+
EntityCopyResponse,
4143
EntityQuery,
4244
EntityQueryResponse,
4345
EntityTypeMetadata,
4446
ErrorReport,
4547
GoogleProjectId,
4648
RawlsRequestContext,
47-
SubmissionValidationEntityInputs
49+
SubmissionValidationEntityInputs,
50+
Workspace
4851
}
4952
import org.broadinstitute.dsde.rawls.util.CollectionUtils
5053
import org.broadinstitute.dsde.rawls.{RawlsException, RawlsExceptionWithErrorReport}
@@ -524,4 +527,13 @@ class DataRepoEntityProvider(snapshotModel: SnapshotModel,
524527

525528
override def batchUpsertEntities(entityUpdates: Seq[EntityUpdateDefinition]): Future[Traversable[Entity]] =
526529
throw new UnsupportedEntityOperationException("batch-upsert entities not supported by this provider.")
530+
531+
override def copyEntities(sourceWorkspaceContext: Workspace,
532+
destWorkspaceContext: Workspace,
533+
entityType: String,
534+
entityNames: Seq[String],
535+
linkExistingEntities: Boolean,
536+
parentContext: RawlsRequestContext
537+
): Future[EntityCopyResponse] =
538+
throw new UnsupportedEntityOperationException("copy entities not supported by this provider.")
527539
}

core/src/main/scala/org/broadinstitute/dsde/rawls/entities/local/LocalEntityProvider.scala

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,20 @@ import org.broadinstitute.dsde.rawls.model.{
2626
AttributeEntityReference,
2727
AttributeValue,
2828
Entity,
29+
EntityCopyDefinition,
30+
EntityCopyResponse,
2931
EntityQuery,
3032
EntityQueryResponse,
3133
EntityQueryResultMetadata,
3234
EntityTypeMetadata,
3335
ErrorReport,
3436
RawlsRequestContext,
37+
SamResourceTypeNames,
38+
SamWorkspaceActions,
3539
SubmissionValidationEntityInputs,
3640
SubmissionValidationValue,
37-
Workspace
41+
Workspace,
42+
WorkspaceAttributeSpecs
3843
}
3944
import org.broadinstitute.dsde.rawls.util.TracingUtils._
4045
import org.broadinstitute.dsde.rawls.util.{AttributeSupport, CollectionUtils, EntitySupport}
@@ -404,4 +409,22 @@ class LocalEntityProvider(requestArguments: EntityRequestArguments,
404409
override def batchUpsertEntities(entityUpdates: Seq[EntityUpdateDefinition]): Future[Traversable[Entity]] =
405410
batchUpdateEntitiesImpl(entityUpdates, upsert = true)
406411

412+
override def copyEntities(sourceWorkspaceContext: Workspace,
413+
destWorkspaceContext: Workspace,
414+
entityType: String,
415+
entityNames: Seq[String],
416+
linkExistingEntities: Boolean,
417+
parentContext: RawlsRequestContext
418+
): Future[EntityCopyResponse] =
419+
traceWithParent("checkAndCopyEntities", parentContext)(_ =>
420+
dataSource.inTransaction { dataAccess =>
421+
dataAccess.entityQuery.checkAndCopyEntities(sourceWorkspaceContext,
422+
destWorkspaceContext,
423+
entityType,
424+
entityNames,
425+
linkExistingEntities,
426+
parentContext
427+
)
428+
}
429+
)
407430
}

core/src/main/scala/org/broadinstitute/dsde/rawls/util/WorkspaceSupport.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,14 @@ trait WorkspaceSupport {
132132
} yield ()
133133

134134
// can't use withClonedAuthDomain because the Auth Domain -> no Auth Domain logic is different
135-
def authDomainCheck(sourceWorkspaceADs: Set[String], destWorkspaceADs: Set[String]): ReadWriteAction[Boolean] =
135+
def authDomainCheck(sourceWorkspaceADs: Set[String], destWorkspaceADs: Set[String]): Boolean =
136136
// if the source has any auth domains, the dest must also *at least* have those auth domains
137-
if (sourceWorkspaceADs.subsetOf(destWorkspaceADs)) DBIO.successful(true)
137+
if (sourceWorkspaceADs.subsetOf(destWorkspaceADs)) true
138138
else {
139139
val missingGroups = sourceWorkspaceADs -- destWorkspaceADs
140140
val errorMsg =
141141
s"Source workspace has an Authorization Domain containing the groups ${missingGroups.mkString(", ")}, which are missing on the destination workspace"
142-
DBIO.failed(new RawlsExceptionWithErrorReport(ErrorReport(StatusCodes.UnprocessableEntity, errorMsg)))
142+
throw new RawlsExceptionWithErrorReport(ErrorReport(StatusCodes.UnprocessableEntity, errorMsg))
143143
}
144144

145145
// WorkspaceContext helpers

core/src/main/scala/org/broadinstitute/dsde/rawls/webservice/EntityApiService.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ trait EntityApiService extends UserInfoDirectives {
317317
entity(as[EntityCopyDefinition]) { copyDefinition =>
318318
complete {
319319
entityServiceConstructor(ctx)
320-
.copyEntities(copyDefinition, request.uri, linkExistingEntitiesBool)
320+
.copyEntities(copyDefinition, linkExistingEntitiesBool)
321321
.map { response =>
322322
if (
323323
response.hardConflicts.isEmpty && (response.softConflicts.isEmpty || linkExistingEntitiesBool)

core/src/main/scala/org/broadinstitute/dsde/rawls/webservice/RawlsApiService.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import org.broadinstitute.dsde.rawls.billing.BillingProjectOrchestrator
2020
import org.broadinstitute.dsde.rawls.bucketMigration.BucketMigrationService
2121
import org.broadinstitute.dsde.rawls.dataaccess.{ExecutionServiceCluster, SamDAO}
2222
import org.broadinstitute.dsde.rawls.entities.EntityService
23+
import org.broadinstitute.dsde.rawls.entities.exceptions.DataEntityException
2324
import org.broadinstitute.dsde.rawls.genomics.GenomicsService
2425
import org.broadinstitute.dsde.rawls.metrics.InstrumentationDirectives
2526
import org.broadinstitute.dsde.rawls.model.{ApplicationVersion, ErrorReport, RawlsRequestContext, UserInfo}
@@ -62,6 +63,9 @@ object RawlsApiService extends LazyLogging {
6263
Sentry.captureException(wsmApiException)
6364
}
6465
complete(wsmApiException.getCode -> ErrorReport(wsmApiException).copy(stackTrace = Seq()))
66+
case dataEntityException: DataEntityException =>
67+
// propagate only the message; don't include the stack trace
68+
complete(dataEntityException.code -> ErrorReport(dataEntityException.getMessage))
6569
case e: Throwable =>
6670
// so we don't log the error twice when debug is enabled
6771
if (logger.underlying.isDebugEnabled) {

0 commit comments

Comments
 (0)