Skip to content

Commit

Permalink
Merge branch 'develop' into da_CORE-207_tsvOptimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
davidangb authored Dec 17, 2024
2 parents 5a22ef9 + b081de4 commit 323ad5d
Show file tree
Hide file tree
Showing 19 changed files with 107 additions and 910 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ trait FireCloudApiService
with RegisterApiService
with WorkspaceApiService
with MethodConfigurationApiService
with SubmissionApiService
with StatusApiService
with MethodsApiService
with UserApiService
Expand All @@ -80,7 +79,6 @@ trait FireCloudApiService
with CromIamApiService
with HealthApiService
with StaticNotebooksApiService
with PerimeterApiService
with PassthroughApiService {

override lazy val log = LoggerFactory.getLogger(getClass)
Expand Down Expand Up @@ -179,11 +177,9 @@ trait FireCloudApiService
profileRoutes ~
cromIamApiServiceRoutes ~
methodConfigurationRoutes ~
submissionServiceRoutes ~
nihRoutes ~
shareLogServiceRoutes ~
staticNotebooksRoutes ~
perimeterServiceRoutes
staticNotebooksRoutes
}

val routeWrappers: Directive[Unit] =
Expand All @@ -195,7 +191,6 @@ trait FireCloudApiService

def route: server.Route = routeWrappers {
cromIamEngineRoutes ~
tosRoutes ~
exportEntitiesRoutes ~
cromIamEngineRoutes ~
exportEntitiesRoutes ~
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package org.broadinstitute.dsde.firecloud.service

import akka.http.scaladsl.client.RequestBuilding
import akka.http.scaladsl.model.headers.{`Content-Type`, Authorization}
import akka.http.scaladsl.model.{HttpMethod, Uri}
import akka.http.scaladsl.model.Uri
import akka.http.scaladsl.server.{Directives, Route}
import org.broadinstitute.dsde.firecloud.utils.RestJsonClient
import org.parboiled.common.FileUtils
Expand All @@ -20,51 +19,12 @@ object FireCloudDirectiveUtils {
}
toUri(path).toString
}

// TODO: should this pass through any other headers, such as Cookie?
/* This list controls which headers from the original request are passed through to the
* target service. It is important that some headers are NOT passed through:
* - if the Host header is passed through, it will not match the target service's host,
* and some servers - notably App Engine - will reject the request.
* - if headers that control the http protocol such as Accept-Encoding or Connection
* are passed through, they may not reflect reality. The original request may have
* come from a browser that supports different encodings or connection protocols
* than the service-to-service request we're about to make.
* - if headers that inform the target such as User-Agent, Referer or X-Forwarded-For
* are passed through, they will be misleading, as they reflect the original request
* and not the service-to-service request we're about to make.
*/
final val allowedPassthroughHeaders = List(Authorization, `Content-Type`).map(_.lowercaseName)

}

trait FireCloudDirectives extends Directives with RequestBuilding with RestJsonClient {

def passthrough(unencodedPath: String, methods: HttpMethod*): Route =
passthrough(Uri(unencodedPath), methods: _*)

// Danger: it is a common mistake to pass in a URI that omits the query parameters included in the original request to Orch.
// To preserve the query, extract it and attach it to the passthrough URI using `.withQuery(query)`.
def passthrough(uri: Uri, methods: HttpMethod*): Route = methods map { inMethod =>
generateExternalHttpRequestForMethod(uri, inMethod)
} reduce (_ ~ _)

def encodeUri(path: String): String = FireCloudDirectiveUtils.encodeUri(path)

private def generateExternalHttpRequestForMethod(uri: Uri, inMethod: HttpMethod) =
method(inMethod) { requestContext =>
val outgoingRequest = requestContext.request
.withUri(uri)
.withHeaders(
requestContext.request.headers.filter(hdr =>
FireCloudDirectiveUtils.allowedPassthroughHeaders.contains(hdr.lowercaseName())
)
)
requestContext.complete(
unAuthedRequest(outgoingRequest)
) // NOTE: This is actually AUTHED because we pass through the Authorization header
}

def withResourceFileContents(path: String)(innerRoute: String => Route): Route =
innerRoute(FileUtils.readAllTextFromResource(path))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ trait CromIamApiService
with StreamingPassthrough {

lazy val workflowRoot: String = FireCloudConfig.CromIAM.authUrl + "/workflows/v1"
lazy val womtoolRoute: String = FireCloudConfig.CromIAM.authUrl + "/womtool/v1"
lazy val engineRoot: String = FireCloudConfig.CromIAM.baseUrl + "/engine/v1"
lazy val rawlsWorkflowRoot: String = FireCloudConfig.Rawls.authUrl + "/workflows"

Expand Down Expand Up @@ -46,18 +45,7 @@ trait CromIamApiService
streamingPassthrough(Uri.Path(localBase) -> Uri(workflowRoot))
}

val womToolRoute: Route =
pathPrefix("womtool" / Segment) { _ =>
path("describe") {
pathEnd {
post {
passthrough(s"$womtoolRoute/describe", HttpMethods.POST)
}
}
}
}

val cromIamApiServiceRoutes = rawlsServiceRoute ~ cromIamServiceRoutes ~ womToolRoute
val cromIamApiServiceRoutes = rawlsServiceRoute ~ cromIamServiceRoutes

val cromIamEngineRoutes: Route =
pathPrefix("engine" / Segment) { _ =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import org.broadinstitute.dsde.firecloud.FireCloudConfig
import org.broadinstitute.dsde.firecloud.model.ModelJsonProtocol._
import org.broadinstitute.dsde.firecloud.model._
import org.broadinstitute.dsde.firecloud.service.FireCloudDirectives
import org.broadinstitute.dsde.firecloud.utils.{RestJsonClient, StandardUserInfoDirectives}
import org.broadinstitute.dsde.firecloud.utils.{RestJsonClient, StandardUserInfoDirectives, StreamingPassthrough}
import org.broadinstitute.dsde.rawls.model.WorkspaceName
import org.slf4j.LoggerFactory

Expand Down Expand Up @@ -93,100 +93,67 @@ trait MethodConfigurationApiService
extends FireCloudDirectives
with SprayJsonSupport
with StandardUserInfoDirectives
with StreamingPassthrough
with RestJsonClient {

final private val ApiPrefix = "workspaces"
lazy val log = LoggerFactory.getLogger(getClass)

val methodConfigurationRoutes: Route = requireUserInfo() { userInfo =>
path("template") {
passthrough(MethodConfigurationApiService.remoteTemplateURL, HttpMethods.POST)
} ~
path("inputsOutputs") {
passthrough(MethodConfigurationApiService.remoteInputsOutputsURL, HttpMethods.POST)
} ~
pathPrefix(ApiPrefix) {
pathPrefix(Segment / Segment / "method_configs") { (workspaceNamespace, workspaceName) =>
path("copyFromMethodRepo") {
post {
entity(as[CopyConfigurationIngest]) { ingest =>
val copyMethodConfig = new MethodConfigurationCopy(
methodRepoName = ingest.configurationName,
methodRepoNamespace = ingest.configurationNamespace,
methodRepoSnapshotId = ingest.configurationSnapshotId,
destination = Option(
MethodConfigurationId(
name = ingest.destinationName,
namespace = ingest.destinationNamespace,
workspaceName = Option(WorkspaceName(namespace = workspaceNamespace, name = workspaceName))
)
pathPrefix(ApiPrefix) {
pathPrefix(Segment / Segment / "method_configs") { (workspaceNamespace, workspaceName) =>
path("copyFromMethodRepo") {
post {
entity(as[CopyConfigurationIngest]) { ingest =>
val copyMethodConfig = new MethodConfigurationCopy(
methodRepoName = ingest.configurationName,
methodRepoNamespace = ingest.configurationNamespace,
methodRepoSnapshotId = ingest.configurationSnapshotId,
destination = Option(
MethodConfigurationId(
name = ingest.destinationName,
namespace = ingest.destinationNamespace,
workspaceName = Option(WorkspaceName(namespace = workspaceNamespace, name = workspaceName))
)
)
val extReq = Post(MethodConfigurationApiService.remoteCopyFromMethodRepoConfigUrl, copyMethodConfig)
)
val extReq = Post(MethodConfigurationApiService.remoteCopyFromMethodRepoConfigUrl, copyMethodConfig)

complete(userAuthedRequest(extReq)(userInfo))
}
complete(userAuthedRequest(extReq)(userInfo))
}
} ~ path("copyToMethodRepo") {
post {
entity(as[PublishConfigurationIngest]) { ingest =>
val copyMethodConfig = new MethodConfigurationPublish(
methodRepoName = ingest.configurationName,
methodRepoNamespace = ingest.configurationNamespace,
source = Option(
MethodConfigurationId(name = ingest.sourceName,
namespace = ingest.sourceNamespace,
workspaceName =
Option(WorkspaceName(namespace = workspaceNamespace, name = workspaceName))
)
}
} ~ path("copyToMethodRepo") {
post {
entity(as[PublishConfigurationIngest]) { ingest =>
val copyMethodConfig = new MethodConfigurationPublish(
methodRepoName = ingest.configurationName,
methodRepoNamespace = ingest.configurationNamespace,
source = Option(
MethodConfigurationId(name = ingest.sourceName,
namespace = ingest.sourceNamespace,
workspaceName =
Option(WorkspaceName(namespace = workspaceNamespace, name = workspaceName))
)
)
val extReq = Post(MethodConfigurationApiService.remoteCopyToMethodRepoConfigUrl, copyMethodConfig)
)
val extReq = Post(MethodConfigurationApiService.remoteCopyToMethodRepoConfigUrl, copyMethodConfig)

complete(userAuthedRequest(extReq)(userInfo))
}
complete(userAuthedRequest(extReq)(userInfo))
}
} ~ pathPrefix(Segment / Segment) { (configNamespace, configName) =>
pathEnd {
passthrough(
encodeUri(
MethodConfigurationApiService.remoteMethodConfigUrl(workspaceNamespace,
workspaceName,
configNamespace,
configName
)
),
HttpMethods.GET,
HttpMethods.PUT,
HttpMethods.POST,
HttpMethods.DELETE
)
} ~
path("rename") {
passthrough(encodeUri(
MethodConfigurationApiService.remoteMethodConfigRenameUrl(workspaceNamespace,
workspaceName,
configNamespace,
configName
)
),
HttpMethods.POST
)
} ~
path("validate") {
passthrough(encodeUri(
MethodConfigurationApiService.remoteMethodConfigValidateUrl(workspaceNamespace,
workspaceName,
configNamespace,
configName
)
),
HttpMethods.GET
)
}
}
} ~ pathPrefix(Segment / Segment) { (configNamespace, configName) =>
streamingPassthrough(
encodeUri(
MethodConfigurationApiService.remoteMethodConfigUrl(workspaceNamespace,
workspaceName,
configNamespace,
configName
)
)
)
}
}
}
}

}
Loading

0 comments on commit 323ad5d

Please sign in to comment.