Skip to content

Commit

Permalink
IA-Add google2 code for disk management (#305)
Browse files Browse the repository at this point in the history
* add new DiskService and begin DiskInterpreter

* rest of interpreter methods

* rm disk operations from GoogleComputeInterpreter

* rm unused method

* version bump, readme and changelog

* fix listDisks

* version bump consistency

* rm duplicate ZoneName

* println in listDisks for debug, ManualTestImports object for testing (TEMP)

* check if nextPageToken is empty before making another request

* fix listDisks and remove manualTestImports object

* add traceId to testing locally readme

* change version to 0.10

* change version in settings

* uncomment line

* update listDisks to only use .iterateAll, rm unused imports, rm protected from KubernetesServiceKindName

Co-authored-by: Gabriela <gcarrill@broadinstitute.org>
  • Loading branch information
gpcarr and gpcarr committed May 19, 2020
1 parent 395bd04 commit b09d90f
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 26 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ To depend on the `MockGoogle*` classes, additionally depend on:

Contains utility functions for talking to Google APIs via com.google.cloud client library (more recent) via gRPC.

Latest SBT dependency: `"org.broadinstitute.dsde.workbench" %% "workbench-google2" % "0.9-e66171c"`
Latest SBT dependency: `"org.broadinstitute.dsde.workbench" %% "workbench-google2" % "0.10-TRAVIS-REPLACE-ME"`

To start the Google PubSub emulator for unit testing:

Expand Down
10 changes: 10 additions & 0 deletions google2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

This file documents changes to the `workbench-google2` library, including notes on how to upgrade to new versions.

## 0.10
Changed:
- Move `resizeDisk` from `GoogleComputeService` to `GoogleDiskService`

Added:
- Add `GoogleDiskService` and `GoogleDiskInterpreter`
- Add `{create,delete}Disk` and `listDisks` to `GoogleDiskService`

SBT dependency: `"org.broadinstitute.dsde.workbench" %% "workbench-google2" % "0.10-TRAVIS-REPLACE-ME"`

## 1.0
Changed:
- Renamed KubernetesSerializableName extension classes
Expand Down
4 changes: 4 additions & 0 deletions google2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,14 @@ import cats.effect.IO
import org.broadinstitute.dsde.workbench.model.google.GcsBucketName
import org.broadinstitute.dsde.workbench.google2.GcsBlobName
import org.broadinstitute.dsde.workbench.model.google.GoogleProject
import cats.mtl.ApplicativeAsk
import java.util.UUID
import org.broadinstitute.dsde.workbench.model.TraceId
import cats.effect.Blocker
implicit val cs = IO.contextShift(global)
implicit val t = IO.timer(global)
implicit def logger = Slf4jLogger.getLogger[IO]
implicit val traceId = ApplicativeAsk.const[IO, TraceId](TraceId(UUID.randomUUID()))
val blocker = Blocker.liftExecutionContext(global)
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import scala.concurrent.duration.FiniteDuration
private[google2] class GoogleComputeInterpreter[F[_]: Async: StructuredLogger: Timer: ContextShift](
instanceClient: InstanceClient,
firewallClient: FirewallClient,
diskClient: DiskClient,
zoneClient: ZoneClient,
machineTypeClient: MachineTypeClient,
networkClient: NetworkClient,
Expand Down Expand Up @@ -174,17 +173,6 @@ private[google2] class GoogleComputeInterpreter[F[_]: Async: StructuredLogger: T
)
}

override def resizeDisk(project: GoogleProject, zone: ZoneName, diskName: DiskName, newSizeGb: Int)(
implicit ev: ApplicativeAsk[F, TraceId]
): F[Unit] = {
val projectZoneDiskName = ProjectZoneDiskName.of(diskName.value, project.value, zone.value)
val request = DisksResizeRequest.newBuilder().setSizeGb(newSizeGb.toString).build()
retryF(
Async[F].delay(diskClient.resizeDisk(projectZoneDiskName, request)),
s"com.google.cloud.compute.v1.DiskClient.resizeDisk(${projectZoneDiskName.toString}, $newSizeGb)"
)
}

override def getZones(project: GoogleProject,
regionName: RegionName)(implicit ev: ApplicativeAsk[F, TraceId]): F[List[Zone]] = {
val request = ListZonesHttpRequest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,6 @@ trait GoogleComputeService[F[_]] {
implicit ev: ApplicativeAsk[F, TraceId]
): F[Option[MachineType]]

def resizeDisk(project: GoogleProject, zone: ZoneName, diskName: DiskName, newSizeGb: Int)(
implicit ev: ApplicativeAsk[F, TraceId]
): F[Unit]

def getZones(project: GoogleProject, regionName: RegionName)(implicit ev: ApplicativeAsk[F, TraceId]): F[List[Zone]]

def getNetwork(project: GoogleProject, networkName: NetworkName)(
Expand Down Expand Up @@ -149,10 +145,6 @@ object GoogleComputeService {
.newBuilder()
.setCredentialsProvider(credentialsProvider)
.build()
val diskSettings = DiskSettings
.newBuilder()
.setCredentialsProvider(credentialsProvider)
.build()
val zoneSettings = ZoneSettings
.newBuilder()
.setCredentialsProvider(credentialsProvider)
Expand Down Expand Up @@ -185,7 +177,6 @@ object GoogleComputeService {
for {
instanceClient <- backgroundResourceF(InstanceClient.create(instanceSettings))
firewallClient <- backgroundResourceF(FirewallClient.create(firewallSettings))
diskClient <- backgroundResourceF(DiskClient.create(diskSettings))
zoneClient <- backgroundResourceF(ZoneClient.create(zoneSettings))
machineTypeClient <- backgroundResourceF(MachineTypeClient.create(machineTypeSettings))
networkClient <- backgroundResourceF(NetworkClient.create(networkSettings))
Expand All @@ -195,7 +186,6 @@ object GoogleComputeService {
globalOperationClient <- backgroundResourceF(GlobalOperationClient.create(globalOperationSettings))
} yield new GoogleComputeInterpreter[F](instanceClient,
firewallClient,
diskClient,
zoneClient,
machineTypeClient,
networkClient,
Expand All @@ -210,7 +200,6 @@ object GoogleComputeService {
}

final case class InstanceName(value: String) extends AnyVal
final case class DiskName(value: String) extends AnyVal
final case class ZoneName(value: String) extends AnyVal
final case class FirewallRuleName(value: String) extends AnyVal
final case class MachineTypeName(value: String) extends AnyVal
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package org.broadinstitute.dsde.workbench.google2

import cats.effect.concurrent.Semaphore
import cats.effect.{Async, Blocker, ContextShift, Timer}
import cats.mtl.ApplicativeAsk
import com.google.cloud.compute.v1.{Disk, DiskClient, DisksResizeRequest, Operation, ProjectZoneDiskName, ProjectZoneName}
import fs2.Stream
import io.chrisdavenport.log4cats.StructuredLogger
import org.broadinstitute.dsde.workbench.RetryConfig
import org.broadinstitute.dsde.workbench.model.TraceId
import org.broadinstitute.dsde.workbench.model.google.GoogleProject

import scala.collection.JavaConverters._

private[google2] class GoogleDiskInterpreter[F[_]: Async: StructuredLogger: Timer: ContextShift] (
diskClient: DiskClient,
retryConfig: RetryConfig,
blocker: Blocker,
blockerBound: Semaphore[F]
) extends GoogleDiskService[F] {

override def createDisk(project: GoogleProject, zone: ZoneName, disk: Disk)
(implicit ev: ApplicativeAsk[F, TraceId]
): F[Operation] = {
val projectZone = ProjectZoneName.of(project.value, zone.value)
retryF(
Async[F].delay(diskClient.insertDisk(projectZone, disk)),
s"com.google.cloud.compute.v1DiskClient.insertDisk(${projectZone.toString}, ${disk.getName})"
).compile.lastOrError
}

override def deleteDisk(project: GoogleProject, zone: ZoneName, diskName: DiskName)(
implicit ev: ApplicativeAsk[F, TraceId]
): F[Operation] = {
val projectZoneDiskName = ProjectZoneDiskName.of(diskName.value, project.value, zone.value)
retryF(
Async[F].delay(diskClient.deleteDisk(projectZoneDiskName)),
s"com.google.cloud.compute.v1.DiskClient.deleteDisk(${projectZoneDiskName.toString})"
).compile.lastOrError
}

override def listDisks(project: GoogleProject, zone: ZoneName)(
implicit ev: ApplicativeAsk[F, TraceId]
): Stream[F, Disk] = {
val projectZone = ProjectZoneName.of(project.value, zone.value)
for {
pagedResults <- retryF(
Async[F].delay(diskClient.listDisks(projectZone)),
s"com.google.cloud.compute.v1.DiskClient.listDisks(${projectZone.toString})"
)

res <- Stream.fromIterator[F](pagedResults.iterateAll().iterator().asScala)
} yield res
}

override def resizeDisk(project: GoogleProject, zone: ZoneName, diskName: DiskName, newSizeGb: Int)(
implicit ev: ApplicativeAsk[F, TraceId]
): F[Operation] = {
val projectZoneDiskName = ProjectZoneDiskName.of(diskName.value, project.value, zone.value)
val request = DisksResizeRequest.newBuilder().setSizeGb(newSizeGb.toString).build()
retryF(
Async[F].delay(diskClient.resizeDisk(projectZoneDiskName, request)),
s"com.google.cloud.compute.v1.DiskClient.resizeDisk(${projectZoneDiskName.toString}, $newSizeGb)"
).compile.lastOrError
}

private def retryF[A](fa: F[A], loggingMsg: String)(implicit ev: ApplicativeAsk[F, TraceId]): Stream[F, A] =
tracedRetryGoogleF(retryConfig)(blockerBound.withPermit(blocker.blockOn(fa)), loggingMsg)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package org.broadinstitute.dsde.workbench.google2

import cats.effect.concurrent.Semaphore
import cats.effect.{Async, Blocker, ContextShift, Resource, Timer}
import cats.mtl.ApplicativeAsk
import com.google.api.gax.core.FixedCredentialsProvider
import com.google.api.services.compute.ComputeScopes
import com.google.auth.oauth2.GoogleCredentials
import org.broadinstitute.dsde.workbench.model.google.GoogleProject
import com.google.cloud.compute.v1._
import fs2.Stream
import io.chrisdavenport.log4cats.StructuredLogger
import org.broadinstitute.dsde.workbench.RetryConfig
import org.broadinstitute.dsde.workbench.google2.util.RetryPredicates
import org.broadinstitute.dsde.workbench.model.TraceId

import scala.collection.JavaConverters._

/**
* Algebra for Google Disk access.
*/
trait GoogleDiskService[F[_]] {
def createDisk(project: GoogleProject, zone: ZoneName, disk: Disk)(
implicit ev: ApplicativeAsk[F, TraceId]
): F[Operation]

def deleteDisk(project: GoogleProject, zone: ZoneName, diskName: DiskName)(
implicit ev: ApplicativeAsk[F, TraceId]
): F[Operation]

def listDisks(project: GoogleProject, zone: ZoneName)(
implicit ev: ApplicativeAsk[F, TraceId]
): Stream[F, Disk]

def resizeDisk(project: GoogleProject, zone: ZoneName, diskName: DiskName, newSizeGb: Int)(
implicit ev: ApplicativeAsk[F, TraceId]
): F[Operation]
}

object GoogleDiskService {
def resource[F[_]: StructuredLogger: Async: Timer: ContextShift](
pathToCredential: String,
blocker: Blocker,
blockerBound: Semaphore[F],
retryConfig: RetryConfig = RetryPredicates.standardRetryConfig): Resource[F, GoogleDiskService[F]] =
for {
credential <- credentialResource(pathToCredential)
scopedCredential = credential.createScoped(Seq(ComputeScopes.COMPUTE).asJava)
interpreter <- fromCredential(scopedCredential, blocker, blockerBound, retryConfig)
} yield interpreter

private def fromCredential[F[_]: StructuredLogger: Async: Timer: ContextShift](
googleCredentials: GoogleCredentials,
blocker: Blocker,
blockerBound: Semaphore[F],
retryConfig: RetryConfig
): Resource[F, GoogleDiskService[F]] = {
val credentialsProvider = FixedCredentialsProvider.create(googleCredentials)

val diskSettings = DiskSettings
.newBuilder()
.setCredentialsProvider(credentialsProvider)
.build()

for {
diskClient <- backgroundResourceF(DiskClient.create(diskSettings))
} yield new GoogleDiskInterpreter[F](
diskClient,
retryConfig,
blocker,
blockerBound
)
}
}

final case class DiskName(value: String) extends AnyVal
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ object KubernetesModels {

final case class KubernetesSelector(labels: Map[String, String])

final protected case class KubernetesServiceKindName(value: String)
final case class KubernetesServiceKindName(value: String)

final case class KubernetesApiServerIp(value: String) {
val url = s"https://${value}"
Expand Down
2 changes: 1 addition & 1 deletion project/Settings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ object Settings {
val google2Settings = only212 ++ commonSettings ++ List(
name := "workbench-google2",
libraryDependencies ++= google2Dependencies,
version := createVersion("1.0")
version := createVersion("0.10")
) ++ publishSettings

val newrelicSettings = only212 ++ commonSettings ++ List(
Expand Down

0 comments on commit b09d90f

Please sign in to comment.