Skip to content

Commit

Permalink
Initial 3.0.0-beta1 release - migrates from Akka to Pekko nightly build
Browse files Browse the repository at this point in the history
  • Loading branch information
doriordan committed Mar 27, 2023
1 parent 5e69b83 commit c4a65b3
Show file tree
Hide file tree
Showing 51 changed files with 216 additions and 1,051 deletions.
2 changes: 1 addition & 1 deletion Quickstart.sc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/
import $ivy.`io.skuber::skuber:2.0.10`, skuber._, skuber.json.format._

import akka.actor.ActorSystem
import org.apache.pekko.actor.ActorSystem
import api.Configuration
import scala.concurrent.Future
import scala.util.{Success, Failure}
Expand Down
34 changes: 20 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ See the [programming guide](docs/GUIDE.md) for more details.

## Example

This example lists pods in `kube-system` namespace:
This example (for Skuber 3.x) lists pods in `kube-system` namespace:

```scala
import skuber._
import skuber.json.format._
import akka.actor.ActorSystem
import org.apache.pekko.actor.ActorSystem
import scala.util.{Success, Failure}

implicit val system = ActorSystem()
Expand Down Expand Up @@ -107,31 +107,38 @@ For other Kubernetes setups, see the [configuration guide](docs/Configuration.md

## Prerequisites

- Java 8
- Java 8 or higher
- Kubernetes cluster

A Kubernetes cluster is needed at runtime. For local development purposes, minikube is recommended.
To get minikube follow the instructions [here](https://github.com/kubernetes/minikube)
A Kubernetes cluster is needed at runtime. For local development purposes, `kind` is recommended.
To install `kind` follow the instructions [here](https://kind.sigs.k8s.io/docs/user/quick-start/).

## Release

You can use the latest release (for 2.12 or 2.13) by adding to your build:
You can use the latest full 2.x release (for Scala 2.12 or 2.13) by adding to your build:

```sbt
libraryDependencies += "io.skuber" %% "skuber" % "2.6.7"
```

Meanwhile users of skuber v1 can continue to use the final v1.x release, which is available only on Scala 2.11:
Meanwhile a pre-release of 3.x (which moves away from Akka to Pekko) is now available:

```sbt
libraryDependencies += "io.skuber" % "skuber_2.11" % "1.7.1"
libraryDependencies += "io.skuber" % "skuber" % "3.0.0-beta1"
```

NOTE: Skuber 2 supports Scala 2.13 since v2.4.0 - support for Scala 2.11 has now been removed since v2.6.0.
The pre-release currently uses a nightly build of Pekko as no full release is yet available - as such it is not recommended for production use but can be used for testing migration of your stack away from Akka.
A full release of Skuber 3.x will be made available when Pekko has an official release.

## Migrating to release v2
NOTE: Skuber supports Scala 2.13 since 2.4.0 - support for Scala 2.11 has now been removed since 2.6.0.

If you have an application using the legacy version v1 of Skuber and want to move to v2, then check out the [migration guide](docs/MIGRATION_1-to-2.md).
## Migrating from release 2.x to 3.x

Skuber 3.x is mostly backwards-compatible with 2.x, except that it replaces all of its uses of Akka with [Pekko](https://github.com/apache/incubator-pekko).
In practice this normally requires minimal changes to your application to migrate to 3.x:

- rename Akka imports e.g. `import akka.actor.ActorSystem` becomes `import org.apache.pekko.actor.ActorSystem`
- rename any `akka` section(s) of your application configuration (`application.conf` file) that relate to skuber to `pekko`.

## Building

Expand All @@ -141,7 +148,6 @@ Building the library from source is very straightforward. Simply run `sbt test`i

This code is licensed under the Apache V2.0 license, a copy of which is included [here](LICENSE.txt).

## IMPORTANT: Akka License Model Changes

Lightbend have moved Akka versions starting from 2.7.x from an Apache 2.0 to BSL license. Skuber currently uses Akka 2.6.x and it is not planned to move to a BSL licensed Akka version - instead it is planned to migrate Skuber to the Apache Pekko open-source fork once it has a full release.
## IMPORTANT: Akka License Model Changes And Pekko Migration

Lightbend have moved Akka versions starting from 2.7.x from an Apache 2.0 to BSL license. Skuber 2.x uses Akka 2.6.x and it is not planned to move to a BSL licensed Akka version - instead it is planned that Skuber 3.x will move from Akka to the Apache Pekko open-source fork.
75 changes: 42 additions & 33 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,84 +1,93 @@

resolvers += "Typesafe Releases" at "https://repo.typesafe.com/typesafe/releases/"
// resolvers += "Typesafe Releases" at "https://repo.typesafe.com/typesafe/releases/"

val akkaVersion = "2.6.19"
val pekkoGroup = "org.apache.pekko"

val scalaCheck = "org.scalacheck" %% "scalacheck" % "1.15.4"
val specs2 = "org.specs2" %% "specs2-core" % "4.17.0"
val scalaTest = "org.scalatest" %% "scalatest" % "3.2.14"
val pekkoVersion = "0.0.0+26626-3e1231c3-SNAPSHOT"
val pekkoHttpVersion = "0.0.0+4332-87421a76-SNAPSHOT"

// the client API request/response handing uses Pekka Http
val pekkoHttp = pekkoGroup %% "pekko-http" % pekkoHttpVersion

// The `watch` and some other functionality uses Pekko streams
val pekkoStreams = pekkoGroup %% "pekko-stream" % pekkoVersion
val pekkoStreamsTestkit = pekkoGroup %% "pekko-stream-testkit" % pekkoVersion % Test

// Skuber uses Pekko logging, so the examples config uses the Pekko slf4j logger with logback backend
val pekkoSlf4j = pekkoGroup %% "pekko-slf4j" % pekkoVersion
val logback = "ch.qos.logback" % "logback-classic" % "1.4.6" % Runtime

val scalaCheck = "org.scalacheck" %% "scalacheck" % "1.17.0"
val specs2 = "org.specs2" %% "specs2-core" % "4.19.2"
val scalaTest = "org.scalatest" %% "scalatest" % "3.2.15"
val mockito = "org.mockito" % "mockito-core" % "4.6.1"
val scalaTestMockito = "org.scalatestplus" %% "mockito-4-6" % "3.2.14.0"
val akkaStreamTestKit = "com.typesafe.akka" %% "akka-stream-testkit" % akkaVersion
val scalaTestMockito = "org.scalatestplus" %% "mockito-4-6" % "3.2.15.0"

val snakeYaml = "org.yaml" % "snakeyaml" % "2.0"
val commonsIO = "commons-io" % "commons-io" % "2.11.0"
val commonsCodec = "commons-codec" % "commons-codec" % "1.15"

// the client API request/response handing uses Akka Http
val akkaHttp = "com.typesafe.akka" %% "akka-http" % "10.2.9"
val akkaStream = "com.typesafe.akka" %% "akka-stream" % akkaVersion
val akka = "com.typesafe.akka" %% "akka-actor" % akkaVersion

// Skuber uses akka logging, so the examples config uses the akka slf4j logger with logback backend
val akkaSlf4j = "com.typesafe.akka" %% "akka-slf4j" % akkaVersion
val logback = "ch.qos.logback" % "logback-classic" % "1.4.4" % Runtime

// the Json formatters are based on Play Json
val playJson = "com.typesafe.play" %% "play-json" % "2.9.3"
val playJson = "com.typesafe.play" %% "play-json" % "2.9.4"

// Need Java 8 or later as the java.time package is used to represent K8S timestamps
scalacOptions += "-target:jvm-1.8"

scalacOptions in Test ++= Seq("-Yrangepos")
Test / scalacOptions ++= Seq("-Yrangepos")

ThisBuild / version := "2.6.7"
ThisBuild / version := "3.0.0-beta1"

sonatypeProfileName := "io.skuber"

publishMavenStyle in ThisBuild := true
ThisBuild / publishMavenStyle := true

licenses in ThisBuild := Seq("APL2" -> url("http://www.apache.org/licenses/LICENSE-2.0.txt"))
ThisBuild / licenses := Seq("APL2" -> url("http://www.apache.org/licenses/LICENSE-2.0.txt"))

homepage in ThisBuild := Some(url("https://github.com/doriordan"))
ThisBuild / homepage := Some(url("https://github.com/doriordan"))

scmInfo in ThisBuild := Some(
ThisBuild / scmInfo := Some(
ScmInfo(
url("https://github.com/doriordan/skuber"),
"scm:[email protected]:doriordan/skuber.git"
)
)

developers in ThisBuild := List(Developer(id="doriordan", name="David ORiordan", email="[email protected]", url=url("https://github.com/doriordan")))
ThisBuild / developers := List(Developer(id="doriordan", name="David ORiordan", email="[email protected]", url=url("https://github.com/doriordan")))

lazy val commonSettings = Seq(
organization := "io.skuber",
crossScalaVersions := Seq("2.12.17", "2.13.10"),
scalaVersion := "2.13.10",
publishTo := sonatypePublishToBundle.value,
pomIncludeRepository := { _ => false },
Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Flat
Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Flat,
resolvers += "Apache Pekko Snapshots" at "https://repository.apache.org/content/groups/snapshots"
)

lazy val skuberSettings = Seq(
name := "skuber",
libraryDependencies ++= Seq(
akkaHttp, akkaStream, playJson, snakeYaml, commonsIO, commonsCodec,
pekkoHttp, pekkoStreams, playJson, snakeYaml, commonsIO, commonsCodec,
scalaCheck % Test, specs2 % Test, mockito % Test, scalaTestMockito % Test,
akkaStreamTestKit % Test, scalaTest % Test
pekkoStreamsTestkit, scalaTest % Test
).map(_.exclude("commons-logging", "commons-logging"))
)

// This explicit Pekko dependency for the example build is not strictly necessary (the necessary dependencies will be transitively
// inherited from skuber dependency anyway) but clients might opt to explicitly specify such dependencies, for example to override version.
val pekkoActors = pekkoGroup %% "pekko-actor" % pekkoVersion

lazy val examplesSettings = Seq(
name := "skuber-examples",
libraryDependencies ++= Seq(akka, akkaSlf4j, logback)
libraryDependencies ++= Seq(pekkoActors, pekkoSlf4j, logback)
)

// by default run the guestbook example when executing a fat examples JAR
// by default run the deployment examples when executing a fat examples JAR
lazy val examplesAssemblySettings = Seq(
mainClass in assembly := Some("skuber.examples.guestbook.Guestbook")
assembly / mainClass := Some("skuber.examples.deployment.DeploymentExamples")
)

publishArtifact in root := false
root / publishArtifact := false

lazy val root = (project in file("."))
.settings(commonSettings: _*)
Expand All @@ -90,11 +99,11 @@ lazy val skuber= (project in file("client"))
commonSettings,
skuberSettings,
Defaults.itSettings,
libraryDependencies += scalaTest % "it"
libraryDependencies += scalaTest % "it",
)

lazy val examples = (project in file("examples"))
.settings(commonSettings: _*)
.settings(examplesSettings: _*)
.settings(examplesAssemblySettings: _*)
.dependsOn(skuber)
.dependsOn(skuber)
4 changes: 2 additions & 2 deletions client/src/it/scala/skuber/CustomResourceBetaSpec.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package skuber

import akka.stream._
import akka.stream.scaladsl._
import org.apache.pekko.stream._
import org.apache.pekko.stream.scaladsl._
import org.scalatest.concurrent.Eventually
import org.scalatest.matchers.should.Matchers
import play.api.libs.json._
Expand Down
4 changes: 2 additions & 2 deletions client/src/it/scala/skuber/CustomResourceSpec.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package skuber

import akka.stream._
import akka.stream.scaladsl._
import org.apache.pekko.stream._
import org.apache.pekko.stream.scaladsl._
import skuber.apiextensions.v1.CustomResourceDefinition
import org.scalatest.matchers.should.Matchers
import org.scalatest.concurrent.Eventually
Expand Down
4 changes: 2 additions & 2 deletions client/src/it/scala/skuber/ExecSpec.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package skuber

import akka.Done
import akka.stream.scaladsl.{Sink, Source}
import org.apache.pekko.Done
import org.apache.pekko.stream.scaladsl.{Sink, Source}
import org.scalatest.BeforeAndAfterAll
import org.scalatest.concurrent.Eventually
import org.scalatest.matchers.should.Matchers
Expand Down
2 changes: 1 addition & 1 deletion client/src/it/scala/skuber/K8SFixture.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package skuber

import akka.actor.ActorSystem
import org.apache.pekko.actor.ActorSystem
import org.scalatest.FutureOutcome
import com.typesafe.config.ConfigFactory
import org.scalatest.flatspec.FixtureAsyncFlatSpec
Expand Down
2 changes: 1 addition & 1 deletion client/src/it/scala/skuber/PodLogSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package skuber

import java.time.ZonedDateTime

import akka.stream.scaladsl.TcpIdleTimeoutException
import org.apache.pekko.stream.scaladsl.TcpIdleTimeoutException
import com.typesafe.config.ConfigFactory
import org.scalatest.BeforeAndAfterAll
import org.scalatest.concurrent.Eventually
Expand Down
4 changes: 2 additions & 2 deletions client/src/it/scala/skuber/WatchContinuouslySpec.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package skuber

import akka.stream.KillSwitches
import akka.stream.scaladsl.{Keep, Sink}
import org.apache.pekko.stream.KillSwitches
import org.apache.pekko.stream.scaladsl.{Keep, Sink}
import org.scalatest.matchers.should.Matchers
import org.scalatest.concurrent.{Eventually, ScalaFutures}
import org.scalatest.time.{Seconds, Span}
Expand Down
4 changes: 2 additions & 2 deletions client/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
skuber {

akka {
# The ID of the dispatcher to use by Skuber. If undefined or empty the default Akka dispatcher is used.
pekko {
# The ID of the dispatcher to use by Skuber. If undefined or empty the default Pekko dispatcher is used.
dispatcher = ""
}

Expand Down
26 changes: 13 additions & 13 deletions client/src/main/scala/skuber/api/client/KubernetesClient.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package skuber.api.client

import akka.stream.scaladsl.{Sink, Source}
import akka.util.ByteString
import org.apache.pekko.stream.scaladsl.{Sink, Source}
import org.apache.pekko.util.ByteString
import play.api.libs.json.{Writes,Format}
import skuber.{DeleteOptions, HasStatusSubresource, LabelSelector, ListOptions, ListResource, ObjectResource, Pod, ResourceDefinition, Scale}
import skuber.api.patch.Patch
Expand Down Expand Up @@ -176,7 +176,7 @@ trait KubernetesClient {
* timeouts - the source returned by this method will complete in the presence of such timeouts or other disconnections.
* @param obj the name of the object to watch
* @tparam O the type of the object to watch e.g. Pod, Deployment
* @return A future containing an Akka streams Source of WatchEvents that will be emitted
* @return A future containing a Pekko streams Source of WatchEvents that will be emitted
*/
def watch[O <: ObjectResource](obj: O)(implicit fmt: Format[O], rd: ResourceDefinition[O], lc: LoggingContext): Future[Source[WatchEvent[O], _]]

Expand All @@ -191,7 +191,7 @@ trait KubernetesClient {
* be produced for an already existing object followed by events for any future changes.
* @param bufSize An optional buffer size for the returned on-the-wire representation of each modified object - normally the default is more than enough.
* @tparam O the type of the resource to watch
* @return A future containing an Akka streams Source of WatchEvents that will be emitted
* @return A future containing a Pekko streams Source of WatchEvents that will be emitted
*/
def watch[O <: ObjectResource](name: String, sinceResourceVersion: Option[String] = None, bufSize: Int = 10000)(
implicit fmt: Format[O], rd: ResourceDefinition[O], lc: LoggingContext): Future[Source[WatchEvent[O], _]]
Expand All @@ -207,7 +207,7 @@ trait KubernetesClient {
* be produced for an already existing object followed by events for any future changes.
* @param bufSize optional buffer size for each modified object received, normally the default is more than enough
* @tparam O the type of resource to watch e.g. Pod, Dpeloyment
* @return A future containing an Akka streams Source of WatchEvents that will be emitted
* @return A future containing a Pekko streams Source of WatchEvents that will be emitted
*/
def watchAll[O <: ObjectResource](sinceResourceVersion: Option[String] = None, bufSize: Int = 10000)(
implicit fmt: Format[O], rd: ResourceDefinition[O], lc: LoggingContext): Future[Source[WatchEvent[O], _]]
Expand All @@ -217,7 +217,7 @@ trait KubernetesClient {
* events on any updates to the object even if the server times out, by transparently restarting the watch as needed.
* @param obj the object resource to watch
* @tparam O the type of the resource e.g Pod
* @return A future containing an Akka streams Source of WatchEvents that will be emitted
* @return A future containing a Pekko streams Source of WatchEvents that will be emitted
*/
def watchContinuously[O <: ObjectResource](obj: O)(implicit fmt: Format[O], rd: ResourceDefinition[O], lc: LoggingContext): Source[WatchEvent[O], _]

Expand All @@ -233,7 +233,7 @@ trait KubernetesClient {
* a single ADDED event will be produced for an already existing object followed by events for any future changes.
* @param bufSize optional buffer size for received object updates, normally the default is more than enough
* @tparam O the type of the resource
* @return A future containing an Akka streams Source of WatchEvents that will be emitted
* @return A future containing a Pekka streams Source of WatchEvents that will be emitted
*/
def watchContinuously[O <: ObjectResource](name: String, sinceResourceVersion: Option[String] = None, bufSize: Int = 10000)(
implicit fmt: Format[O], rd: ResourceDefinition[O], lc: LoggingContext): Source[WatchEvent[O], _]
Expand All @@ -249,7 +249,7 @@ trait KubernetesClient {
* a single ADDED event will be produced for an already existing object followed by events for any future changes.
* @param bufSize optional buffer size for received object updates, normally the default is more than enough
* @tparam O the type pf the resource
* @return A future containing an Akka streams Source of WatchEvents that will be emitted
* @return A future containing a Pekko streams Source of WatchEvents that will be emitted
*/
def watchAllContinuously[O <: ObjectResource](sinceResourceVersion: Option[String] = None, bufSize: Int = 10000)(
implicit fmt: Format[O], rd: ResourceDefinition[O], lc: LoggingContext): Source[WatchEvent[O], _]
Expand All @@ -262,7 +262,7 @@ trait KubernetesClient {
* ensures a watch is always requested on the server.
* @param bufsize optional buffer size for received object updates, normally the default is more than enough
* @tparam O the resource type to watch
* @return A future containing an Akka streams Source of WatchEvents that will be emitted
* @return A future containing a Pekko streams Source of WatchEvents that will be emitted
*/
def watchWithOptions[O <: ObjectResource](options: ListOptions, bufsize: Int = 10000)(
implicit fmt: Format[O], rd: ResourceDefinition[O], lc: LoggingContext): Source[WatchEvent[O], _]
Expand Down Expand Up @@ -320,7 +320,7 @@ trait KubernetesClient {
def jsonMergePatch[O <: ObjectResource](obj: O, patch: String)(implicit rd: ResourceDefinition[O], fmt: Format[O], lc: LoggingContext): Future[O]

/**
* Get the logs from a pod (similar to `kubectl logs ...`). The logs are streamed using an Akka streams source
* Get the logs from a pod (similar to `kubectl logs ...`). The logs are streamed using a Pekko streams source
* @param name the name of the pod
* @param queryParams optional parameters of the request (for example container name)
* @param namespace if set this specifies the namespace of the pod (otherwise the configured namespace is used)
Expand All @@ -333,9 +333,9 @@ trait KubernetesClient {
* @param podName the name of the pod
* @param command the command to execute
* @param maybeContainerName an optional container name
* @param maybeStdin optional Akka Source for sending input to stdin for the command
* @param maybeStdout optional Akka Sink to receive output from stdout for the command
* @param maybeStderr optional Akka Sink to receive output from stderr for the command
* @param maybeStdin optional Pekko Source for sending input to stdin for the command
* @param maybeStdout optional Pekko Sink to receive output from stdout for the command
* @param maybeStderr optional Pekko Sink to receive output from stderr for the command
* @param tty optionally set tty on
* @param maybeClose if set, this can be used to close the connection to the pod by completing the promise
* @return A future indicating the exec command has been submitted
Expand Down
Loading

0 comments on commit c4a65b3

Please sign in to comment.