Skip to content

Commit

Permalink
Updated BQ, PubSub, DP modules and added Batch Module (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
tharwaninitin authored Dec 21, 2023
1 parent 231144b commit 8642073
Show file tree
Hide file tree
Showing 29 changed files with 560 additions and 173 deletions.
2 changes: 1 addition & 1 deletion .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
version = 3.3.1
runner.dialect = scala212
maxColumn = 130
maxColumn = 150
project.git = true
align.preset = more
assumeStandardLibraryStripMargin = true
Expand Down
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,24 @@ Add the latest release as a dependency to your project
| PubSub | [![Latest Version](https://maven-badges.herokuapp.com/maven-central/com.github.tharwaninitin/gcp4zio-pubsub_2.12/badge.svg)](https://mvnrepository.com/artifact/com.github.tharwaninitin/gcp4zio-pubsub) | [![javadoc](https://javadoc.io/badge2/com.github.tharwaninitin/gcp4zio-pubsub_2.12/javadoc.svg)](https://javadoc.io/doc/com.github.tharwaninitin/gcp4zio-pubsub_2.12) | [![gcp4zio-pubsub Scala version support](https://index.scala-lang.org/tharwaninitin/gcp4zio/gcp4zio-pubsub/latest-by-scala-version.svg)](https://index.scala-lang.org/tharwaninitin/gcp4zio/gcp4zio-pubsub) |
| Cloud Monitoring | [![Latest Version](https://maven-badges.herokuapp.com/maven-central/com.github.tharwaninitin/gcp4zio-monitoring_2.12/badge.svg)](https://mvnrepository.com/artifact/com.github.tharwaninitin/gcp4zio-monitoring) | [![javadoc](https://javadoc.io/badge2/com.github.tharwaninitin/gcp4zio-monitoring_2.12/javadoc.svg)](https://javadoc.io/doc/com.github.tharwaninitin/gcp4zio-monitoring_2.12) | [![gcp4zio-monitoring Scala version support](https://index.scala-lang.org/tharwaninitin/gcp4zio/gcp4zio-monitoring/latest-by-scala-version.svg)](https://index.scala-lang.org/tharwaninitin/gcp4zio/gcp4zio-monitoring) |

This project is compiled with scala versions 2.12.17, 2.13.10, 3.2.1
This project is compiled with scala versions 2.12.18, 2.13.12, 3.3.1

__SBT__
``` scala mdoc
libraryDependencies ++= List(
"com.github.tharwaninitin" %% "gcp4zio-gcs" % "1.4.1",
"com.github.tharwaninitin" %% "gcp4zio-dp" % "1.4.1",
"com.github.tharwaninitin" %% "gcp4zio-bq" % "1.4.1",
"com.github.tharwaninitin" %% "gcp4zio-pubsub" % "1.4.1",
"com.github.tharwaninitin" %% "gcp4zio-monitoring" % "1.4.1"
"com.github.tharwaninitin" %% "gcp4zio-gcs" % "1.5.0",
"com.github.tharwaninitin" %% "gcp4zio-dp" % "1.5.0",
"com.github.tharwaninitin" %% "gcp4zio-bq" % "1.5.0",
"com.github.tharwaninitin" %% "gcp4zio-pubsub" % "1.5.0",
"com.github.tharwaninitin" %% "gcp4zio-monitoring" % "1.5.0"
)
```
__Maven__
```
<dependency>
<groupId>com.github.tharwaninitin</groupId>
<artifactId>gcp4zio-gcs_2.12</artifactId>
<version>1.4.1</version>
<version>1.5.0</version>
</dependency>
```
# GCP4ZIO API's
Expand Down Expand Up @@ -180,6 +180,9 @@ import gcp4zio.pubsub.topic._
// Create PubSub Topic
PSTopic.createTopic(project = "gcsProjectId", topic = "topicName")

// Add IAM Policy Binding to existing Topic, where you grant basic pubsub role to a member
PSTopic.addIAMPolicyBindingToTopic(project = "gcsProjectId", topic = "topicName", member = "example@principalAccount.com", role = "roles/<IAM_Role>")

// Delete PubSub Topic
PSTopic.deleteTopic(project = "gcsProjectId", topic = "topicName")
```
Expand Down
23 changes: 18 additions & 5 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import Versions._
Global / onChangedBuildSource := ReloadOnSourceChanges

lazy val commonSettings = Seq(
scalaVersion := Scala212,
crossScalaVersions := AllScalaVersions,
scalaVersion := scala212,
crossScalaVersions := allScalaVersions,
dependencyUpdatesFailBuild := true,
dependencyUpdatesFilter -= moduleFilter(organization = "org.scala-lang"),
scalacOptions ++= {
Expand Down Expand Up @@ -35,7 +35,7 @@ lazy val gcp4zio = (project in file("."))
crossScalaVersions := Nil, // crossScalaVersions must be set to Nil on the aggregating project
publish / skip := true
)
.aggregate(bq, dp, gcs, pubsub, monitoring)
.aggregate(bq, dp, gcs, pubsub, batch, monitoring)

lazy val bq = (project in file("modules/bq"))
.settings(commonSettings)
Expand All @@ -53,17 +53,30 @@ lazy val pubsub = (project in file("modules/pubsub"))
.settings(commonSettings)
.settings(name := "gcp4zio-pubsub", libraryDependencies ++= coreLibs ++ pubSubLibs ++ testLibs)

lazy val batch = (project in file("modules/batch"))
.settings(commonSettings)
.settings(name := "gcp4zio-batch", libraryDependencies ++= coreLibs ++ batchLibs ++ testLibs)

lazy val monitoring = (project in file("modules/monitoring"))
.settings(commonSettings)
.settings(name := "gcp4zio-monitoring", libraryDependencies ++= coreLibs ++ monitoringLibs ++ testLibs)

lazy val examples = (project in file("examples"))
.settings(commonSettings)
.settings(
name := "examples",
publish / skip := true,
libraryDependencies ++= List("ch.qos.logback" % "logback-classic" % logbackVersion)
)
.dependsOn(dp, gcs, pubsub, batch)

lazy val docs = project
.in(file("modules/docs")) // important: it must not be docs/
.dependsOn(bq, dp, gcs, pubsub, monitoring)
.dependsOn(bq, dp, gcs, pubsub, batch, monitoring)
.settings(
name := "gcp4zio-docs",
publish / skip := true,
mdocVariables := Map("VERSION" -> version.value, "Scala212" -> Scala212, "Scala213" -> Scala213, "Scala3" -> Scala3),
mdocVariables := Map("VERSION" -> version.value, "Scala212" -> scala212, "Scala213" -> scala213, "Scala3" -> scala3),
mdocIn := new File("docs/readme.template.md"),
mdocOut := new File("README.md")
)
Expand Down
3 changes: 3 additions & 0 deletions docs/readme.template.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ import gcp4zio.pubsub.topic._
// Create PubSub Topic
PSTopic.createTopic(project = "gcsProjectId", topic = "topicName")

// Add IAM Policy Binding to existing Topic, where you grant basic pubsub role to a member
PSTopic.addIAMPolicyBindingToTopic(project = "gcsProjectId", topic = "topicName", member = "example@principalAccount.com", role = "roles/<IAM_Role>")

// Delete PubSub Topic
PSTopic.deleteTopic(project = "gcsProjectId", topic = "topicName")
```
Expand Down
24 changes: 0 additions & 24 deletions examples.sbt

This file was deleted.

6 changes: 5 additions & 1 deletion examples/src/main/scala/ApplicationLogger.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import org.slf4j.{Logger, LoggerFactory}
import zio.logging.backend.SLF4J
import zio.{Runtime, ULayer}

trait ApplicationLogger {
lazy val logger: Logger = LoggerFactory.getLogger(getClass.getName)
protected val logger: Logger = LoggerFactory.getLogger(getClass.getName)

protected val zioSlf4jLogger: ULayer[Unit] = Runtime.removeDefaultLoggers >>> SLF4J.slf4j
}
35 changes: 35 additions & 0 deletions examples/src/main/scala/GCPCloudBatch.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import gcp4zio.batch.Batch
import zio._
import scala.jdk.CollectionConverters._

// export GOOGLE_APPLICATION_CREDENTIALS=
// export GCP_PROJECT=
// export GCP_REGION=

object GCPCloudBatch extends ZIOAppDefault with ApplicationLogger {

// https://github.com/GoogleCloudPlatform/java-docs-samples/tree/main/batch/snippets/src/main/java
// https://cloud.google.com/batch/docs/create-run-basic-job

override val bootstrap: ULayer[Unit] = zioSlf4jLogger

val gcpProject: String = sys.env("GCP_PROJECT")
val gcpRegion: String = sys.env("GCP_REGION")

val layer: TaskLayer[Batch] = Batch.live(gcpProject, gcpRegion)

override def run: Task[Unit] = (Batch
.createJob(
"example-container-job",
"gcr.io/google-containers/busybox",
List("-c", "echo Hello world! This is task ${BATCH_TASK_INDEX}. This job has a total of ${BATCH_TASK_COUNT} tasks."),
Some("/bin/sh"),
None
) *>
Batch.listJobs
.map(_.foreach(job => logger.info(job.getName + " " + job.getStatus.getStatusEventsList.asScala.toList.mkString))))
.provide(layer)

// override def run: Task[Unit] = Batch.deleteJob("example-container-job").provide(layer).unit

}
5 changes: 2 additions & 3 deletions examples/src/main/scala/PS.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ import gcp4zio.pubsub.subscriber.PSSubscriber
import gcp4zio.pubsub.subscription.PSSubscription
import gcp4zio.pubsub.topic.PSTopic
import zio._
import zio.logging.backend.SLF4J
import java.nio.charset.Charset

@SuppressWarnings(Array("org.wartremover.warts.ToString"))
object PS extends ZIOAppDefault {
object PS extends ZIOAppDefault with ApplicationLogger {

override val bootstrap = Runtime.removeDefaultLoggers >>> SLF4J.slf4j
override val bootstrap: ULayer[Unit] = zioSlf4jLogger

lazy val gcsProject: String = sys.env("GCS_PROJECT")
lazy val subscription: String = sys.env("SUBSCRIPTION")
Expand Down
36 changes: 36 additions & 0 deletions modules/batch/src/main/scala/gcp4zio/batch/Batch.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package gcp4zio.batch

import com.google.cloud.batch.v1.Job
import zio.{RIO, Task, TaskLayer, ZIO, ZLayer}

trait Batch {
def createJob(
name: String,
image: String,
commands: List[String],
entrypoint: Option[String],
serviceAccount: Option[String]
): Task[Job]

def deleteJob(name: String): Task[Unit]

def listJobs: Task[Iterable[Job]]
}

object Batch {
def createJob(
name: String,
image: String,
commands: List[String],
entrypoint: Option[String],
serviceAccount: Option[String]
): RIO[Batch, Job] =
ZIO.serviceWithZIO(_.createJob(name, image, commands, entrypoint, serviceAccount))

def deleteJob(name: String): RIO[Batch, Unit] = ZIO.serviceWithZIO(_.deleteJob(name))

def listJobs: RIO[Batch, Iterable[Job]] = ZIO.serviceWithZIO(_.listJobs)

def live(project: String, region: String): TaskLayer[Batch] =
ZLayer.scoped(BatchClient().map(batch => BatchImpl(batch, project, region)))
}
15 changes: 15 additions & 0 deletions modules/batch/src/main/scala/gcp4zio/batch/BatchClient.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package gcp4zio.batch

import com.google.cloud.batch.v1.BatchServiceClient
import zio.{RIO, Scope, ZIO}

object BatchClient {

/** Returns AutoCloseable BatchServiceClient object wrapped in ZIO
* @return
* RIO[Scope, BatchServiceClient]
*/
def apply(): RIO[Scope, BatchServiceClient] = ZIO.fromAutoCloseable(ZIO.attempt {
BatchServiceClient.create()
})
}
119 changes: 119 additions & 0 deletions modules/batch/src/main/scala/gcp4zio/batch/BatchImpl.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package gcp4zio.batch

import com.google.cloud.batch.v1.AllocationPolicy.{InstancePolicy, InstancePolicyOrTemplate, NetworkInterface, NetworkPolicy}
import com.google.cloud.batch.v1.LogsPolicy.Destination
import com.google.cloud.batch.v1.Runnable.Container
import com.google.cloud.batch.v1._
import com.google.protobuf.Duration
import zio.{Task, ZIO}
import scala.jdk.CollectionConverters._

case class BatchImpl(client: BatchServiceClient, project: String, region: String) extends Batch {
override def createJob(
name: String,
image: String,
commands: List[String],
entrypoint: Option[String],
serviceAccount: Option[String]
): Task[Job] =
ZIO.attempt {
// Define what will be done as part of the job.

val container = entrypoint match {
case Some(value) =>
Container.newBuilder().setImageUri(image).addAllCommands(commands.asJava).setEntrypoint(value).build()
case None => Container.newBuilder().setImageUri(image).addAllCommands(commands.asJava).build()
}

val runnable = Runnable.newBuilder().setContainer(container).build()

// We can specify what resources are requested by each task.
// In milliseconds per cpu-second. This means the task requires 2 whole CPUs.
// In MiB.
val computeResource = ComputeResource.newBuilder().setCpuMilli(2000).setMemoryMib(16).build()

// Jobs can be divided into tasks. In this case, we have only one task.
val task = TaskSpec
.newBuilder()
.addRunnables(runnable)
.setComputeResource(computeResource)
.setMaxRetryCount(0)
.setMaxRunDuration(Duration.newBuilder().setSeconds(3600).build())
.build()

// Tasks are grouped inside a job using TaskGroups.
// Currently, it's possible to have only one task group.
val taskGroup = TaskGroup.newBuilder().setTaskCount(1).setTaskSpec(task).build()

// Policies are used to define on what kind of virtual machines the tasks will run on.
// In this case, we tell the system to use "e2-standard-4" machine type.
// Read more about machine types here: https://cloud.google.com/compute/docs/machine-types
val instancePolicy = InstancePolicy.newBuilder().setMachineType("e2-standard-4").build()

val sa = serviceAccount.map(ServiceAccount.newBuilder().setEmail(_).build())

val ni = NetworkInterface
.newBuilder()
.setNetwork("global/networks/default")
.setSubnetwork("regions/us-central1/subnetworks/default")
.setNoExternalIpAddress(true)
.build()

val np = NetworkPolicy.newBuilder().addNetworkInterfaces(ni)

val allocationPolicy =
sa match {
case Some(value) =>
AllocationPolicy
.newBuilder()
.addInstances(InstancePolicyOrTemplate.newBuilder().setPolicy(instancePolicy).build())
.setServiceAccount(value)
.setNetwork(np)
.build()
case None =>
AllocationPolicy
.newBuilder()
.addInstances(InstancePolicyOrTemplate.newBuilder().setPolicy(instancePolicy).build())
.setNetwork(np)
.build()
}

val job = Job
.newBuilder()
.addTaskGroups(taskGroup)
.setAllocationPolicy(allocationPolicy)
.putLabels("env", "testing")
.putLabels("type", "container")
// We use Cloud Logging as it's an out of the box available option.
.setLogsPolicy(LogsPolicy.newBuilder().setDestination(Destination.CLOUD_LOGGING).build())
.build()

val createJobRequest = CreateJobRequest
.newBuilder()
// The job's parent is the region in which the job will run.
.setParent(String.format("projects/%s/locations/%s", project, region))
.setJob(job)
.setJobId(name)
.build()

logger.info(s"Creating batch job")

val jobResult = client.createJobCallable().call(createJobRequest)

logger.info(s"Successfully created the job ${jobResult.getName}")

jobResult
}

override def deleteJob(name: String): Task[Unit] = {
val jobName = s"projects/$project/locations/$region/jobs/$name"
logger.info(s"Deleting batch job $jobName")
ZIO.fromFutureJava(client.deleteJobAsync(jobName)) *> ZIO.logInfo(s"Deleted batch job: $jobName")
}

override def listJobs: Task[Iterable[Job]] = ZIO.attempt {
val parent = s"projects/$project/locations/$region"
logger.info(s"Listing batch jobs under $parent")
client.listJobs(parent).iterateAll().asScala
}
}
7 changes: 7 additions & 0 deletions modules/batch/src/main/scala/gcp4zio/batch/package.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package gcp4zio

import org.slf4j.{Logger, LoggerFactory}

package object batch {
private[batch] lazy val logger: Logger = LoggerFactory.getLogger(getClass.getName)
}
Loading

0 comments on commit 8642073

Please sign in to comment.