From 4656c29b70f2f5acbc3e3ac722d36eb0a1729cf0 Mon Sep 17 00:00:00 2001 From: David O'Riordan Date: Wed, 19 Oct 2022 15:43:35 +0100 Subject: [PATCH] v2.6.6-rc0 --- build.sbt | 29 +++++------ .../it/scala/skuber/CustomResourceSpec.scala | 4 +- .../src/it/scala/skuber/DeploymentSpec.scala | 2 +- client/src/it/scala/skuber/ExecSpec.scala | 3 +- .../HorizontalPodAutoscalerV2Beta1Spec.scala | 2 +- client/src/it/scala/skuber/K8SFixture.scala | 8 +-- .../src/it/scala/skuber/NamespaceSpec.scala | 2 +- client/src/it/scala/skuber/PatchSpec.scala | 3 +- .../skuber/PodDisruptionBudgetSpec.scala | 2 +- client/src/it/scala/skuber/PodLogSpec.scala | 3 +- client/src/it/scala/skuber/PodSpec.scala | 3 +- client/src/it/scala/skuber/ServiceSpec.scala | 2 +- .../scala/skuber/WatchContinuouslySpec.scala | 2 +- client/src/main/scala/skuber/ConfigMap.scala | 11 ++-- client/src/main/scala/skuber/Container.scala | 50 +++++++++---------- .../main/scala/skuber/CustomResource.scala | 6 +-- client/src/main/scala/skuber/Endpoints.scala | 10 ++-- .../src/main/scala/skuber/EnvFromSource.scala | 5 +- client/src/main/scala/skuber/EnvVar.scala | 4 +- client/src/main/scala/skuber/Event.scala | 25 ++++------ .../src/main/scala/skuber/LabelSelector.scala | 4 +- client/src/main/scala/skuber/LimitRange.scala | 11 ++-- client/src/main/scala/skuber/Namespace.scala | 14 +++--- client/src/main/scala/skuber/Node.scala | 12 ++--- .../main/scala/skuber/PersistentVolume.scala | 13 ++--- .../scala/skuber/PersistentVolumeClaim.scala | 13 ++--- client/src/main/scala/skuber/Pod.scala | 11 ++-- client/src/main/scala/skuber/Resource.scala | 13 ++--- .../scala/skuber/ResourceDefinition.scala | 9 ++-- .../scala/skuber/ResourceSpecification.scala | 12 ++--- client/src/main/scala/skuber/Scale.scala | 13 ++--- client/src/main/scala/skuber/Secret.scala | 11 ++-- client/src/main/scala/skuber/Security.scala | 49 ++++++++---------- .../main/scala/skuber/ServiceAccount.scala | 9 ++-- .../skuber/annotation/NodeAffinity.scala | 6 +-- .../main/scala/skuber/api/Configuration.scala | 25 +++++----- .../skuber/api/client/KubernetesClient.scala | 8 +-- .../skuber/api/client/LoggingConfig.scala | 20 ++++---- .../skuber/api/client/exec/PodExecImpl.scala | 12 ++--- .../client/impl/KubernetesClientImpl.scala | 13 +++-- .../scala/skuber/api/client/package.scala | 7 ++- client/src/main/scala/skuber/api/patch.scala | 4 +- .../skuber/api/security/SecurityHelper.scala | 23 ++++----- .../skuber/api/watch/LongPollingPool.scala | 3 +- .../main/scala/skuber/api/watch/Watch.scala | 12 ++--- .../CustomResourceDefinition.scala | 8 ++- .../main/scala/skuber/apps/Deployment.scala | 2 +- .../main/scala/skuber/apps/StatefulSet.scala | 14 +++--- .../main/scala/skuber/apps/v1/DaemonSet.scala | 14 +++--- .../scala/skuber/apps/v1/Deployment.scala | 13 +++-- .../scala/skuber/apps/v1/ReplicaSet.scala | 12 ++--- .../scala/skuber/apps/v1/StatefulSet.scala | 2 +- .../skuber/apps/v1beta1/Deployment.scala | 8 +-- .../skuber/apps/v1beta1/StatefulSet.scala | 12 +++-- .../autoscaling/HorizontalPodAutoscaler.scala | 16 +++--- .../src/main/scala/skuber/batch/CronJob.scala | 4 +- client/src/main/scala/skuber/batch/Job.scala | 15 +++--- .../main/scala/skuber/batch/JobTemplate.scala | 2 +- .../main/scala/skuber/ext/Deployment.scala | 13 ++--- .../main/scala/skuber/ext/ReplicaSet.scala | 15 +++--- .../src/main/scala/skuber/ext/package.scala | 6 --- .../json/PlayJsonSupportForAkkaHttp.scala | 1 - .../json/annotation/format/package.scala | 9 ++-- .../scala/skuber/networking/Ingress.scala | 5 +- .../skuber/networking/NetworkPolicy.scala | 11 ++-- .../policy/v1beta1/PodDisruptionBudget.scala | 12 +++-- .../main/scala/skuber/rbac/ClusterRole.scala | 8 +-- .../skuber/rbac/ClusterRoleBinding.scala | 10 ++-- .../main/scala/skuber/rbac/PolicyRule.scala | 15 +++--- .../main/scala/skuber/rbac/RoleBinding.scala | 10 ++-- .../src/main/scala/skuber/rbac/RoleRef.scala | 8 +-- .../src/main/scala/skuber/rbac/Subject.scala | 9 +--- .../scala/skuber/settings/PodPreset.scala | 6 +-- .../scala/skuber/api/ConfigurationSpec.scala | 11 ++-- .../deployment/DeploymentExamples.scala | 2 +- project/build.properties | 2 +- project/plugins.sbt | 6 +-- 77 files changed, 371 insertions(+), 413 deletions(-) diff --git a/build.sbt b/build.sbt index 9bd75c0e..6dc2dcb9 100644 --- a/build.sbt +++ b/build.sbt @@ -1,36 +1,37 @@ resolvers += "Typesafe Releases" at "https://repo.typesafe.com/typesafe/releases/" -val akkaVersion = "2.6.15" +val akkaVersion = "2.6.19" val scalaCheck = "org.scalacheck" %% "scalacheck" % "1.15.4" -val specs2 = "org.specs2" %% "specs2-core" % "4.11.0" -val scalaTest = "org.scalatest" %% "scalatest" % "3.0.9" -val mockito = "org.mockito" % "mockito-core" % "3.11.0" +val specs2 = "org.specs2" %% "specs2-core" % "4.17.0" +val scalaTest = "org.scalatest" %% "scalatest" % "3.2.14" +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 snakeYaml = "org.yaml" % "snakeyaml" % "1.31" -val commonsIO = "commons-io" % "commons-io" % "2.9.0" +val snakeYaml = "org.yaml" % "snakeyaml" % "1.33" +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.4" +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.2.3" % Runtime +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.2" +val playJson = "com.typesafe.play" %% "play-json" % "2.9.3" // 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") -ThisBuild / version := "2.6.5" +ThisBuild / version := "2.6.6-rc0" sonatypeProfileName := "io.skuber" @@ -51,8 +52,8 @@ developers in ThisBuild := List(Developer(id="doriordan", name="David ORiordan", lazy val commonSettings = Seq( organization := "io.skuber", - crossScalaVersions := Seq("2.12.13", "2.13.6"), - scalaVersion := "2.13.6", + crossScalaVersions := Seq("2.12.17", "2.13.10"), + scalaVersion := "2.13.10", publishTo := sonatypePublishToBundle.value, pomIncludeRepository := { _ => false }, Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Flat @@ -62,8 +63,8 @@ lazy val skuberSettings = Seq( name := "skuber", libraryDependencies ++= Seq( akkaHttp, akkaStream, playJson, snakeYaml, commonsIO, commonsCodec, - scalaCheck % Test, specs2 % Test, mockito % Test, akkaStreamTestKit % Test, - scalaTest % Test + scalaCheck % Test, specs2 % Test, mockito % Test, scalaTestMockito % Test, + akkaStreamTestKit % Test, scalaTest % Test ).map(_.exclude("commons-logging", "commons-logging")) ) diff --git a/client/src/it/scala/skuber/CustomResourceSpec.scala b/client/src/it/scala/skuber/CustomResourceSpec.scala index 07c780ab..cc69aaee 100644 --- a/client/src/it/scala/skuber/CustomResourceSpec.scala +++ b/client/src/it/scala/skuber/CustomResourceSpec.scala @@ -3,10 +3,10 @@ package skuber import akka.stream._ import akka.stream.scaladsl._ import skuber.apiextensions.CustomResourceDefinition -import org.scalatest.Matchers +import org.scalatest.matchers.should.Matchers import org.scalatest.concurrent.Eventually import play.api.libs.json._ -import skuber.ResourceSpecification.{Subresources,ScaleSubresource} +import skuber.ResourceSpecification.{ScaleSubresource, Subresources} import scala.concurrent.duration._ import scala.concurrent.{Await, Future} diff --git a/client/src/it/scala/skuber/DeploymentSpec.scala b/client/src/it/scala/skuber/DeploymentSpec.scala index 55651bb6..82dd7c4a 100644 --- a/client/src/it/scala/skuber/DeploymentSpec.scala +++ b/client/src/it/scala/skuber/DeploymentSpec.scala @@ -1,6 +1,6 @@ package skuber -import org.scalatest.Matchers +import org.scalatest.matchers.should.Matchers import org.scalatest.concurrent.{Eventually, ScalaFutures} import skuber.LabelSelector.IsEqualRequirement import skuber.apps.v1.Deployment diff --git a/client/src/it/scala/skuber/ExecSpec.scala b/client/src/it/scala/skuber/ExecSpec.scala index 7c699b86..b02c86a8 100644 --- a/client/src/it/scala/skuber/ExecSpec.scala +++ b/client/src/it/scala/skuber/ExecSpec.scala @@ -2,8 +2,9 @@ package skuber import akka.Done import akka.stream.scaladsl.{Sink, Source} -import org.scalatest.{BeforeAndAfterAll, Matchers} +import org.scalatest.BeforeAndAfterAll import org.scalatest.concurrent.Eventually +import org.scalatest.matchers.should.Matchers import skuber.json.format._ import scala.concurrent.duration._ diff --git a/client/src/it/scala/skuber/HorizontalPodAutoscalerV2Beta1Spec.scala b/client/src/it/scala/skuber/HorizontalPodAutoscalerV2Beta1Spec.scala index ac7ef322..8e9545f2 100644 --- a/client/src/it/scala/skuber/HorizontalPodAutoscalerV2Beta1Spec.scala +++ b/client/src/it/scala/skuber/HorizontalPodAutoscalerV2Beta1Spec.scala @@ -1,6 +1,6 @@ package skuber -import org.scalatest.Matchers +import org.scalatest.matchers.should.Matchers import org.scalatest.concurrent.Eventually import skuber.apps.v1.Deployment import skuber.autoscaling.v2beta1.HorizontalPodAutoscaler diff --git a/client/src/it/scala/skuber/K8SFixture.scala b/client/src/it/scala/skuber/K8SFixture.scala index 0bf112eb..3d2e748a 100644 --- a/client/src/it/scala/skuber/K8SFixture.scala +++ b/client/src/it/scala/skuber/K8SFixture.scala @@ -1,12 +1,11 @@ package skuber import akka.actor.ActorSystem -import org.scalatest.{FutureOutcome, fixture} -import skuber.api.client._ +import org.scalatest.FutureOutcome import com.typesafe.config.ConfigFactory -import skuber.api.client.impl.KubernetesClientImpl +import org.scalatest.flatspec.FixtureAsyncFlatSpec -trait K8SFixture extends fixture.AsyncFlatSpec { +trait K8SFixture extends FixtureAsyncFlatSpec { override type FixtureParam = K8SRequestContext @@ -17,6 +16,7 @@ trait K8SFixture extends fixture.AsyncFlatSpec { override def withFixture(test: OneArgAsyncTest): FutureOutcome = { val k8s = k8sInit(config) + complete { withFixture(test.toNoArgAsyncTest(k8s)) } lastly { diff --git a/client/src/it/scala/skuber/NamespaceSpec.scala b/client/src/it/scala/skuber/NamespaceSpec.scala index 0f869b83..2c9e298f 100644 --- a/client/src/it/scala/skuber/NamespaceSpec.scala +++ b/client/src/it/scala/skuber/NamespaceSpec.scala @@ -2,7 +2,7 @@ package skuber import java.util.UUID.randomUUID -import org.scalatest.Matchers +import org.scalatest.matchers.should.Matchers import org.scalatest.concurrent.Eventually import json.format.{namespaceFormat, podFormat} diff --git a/client/src/it/scala/skuber/PatchSpec.scala b/client/src/it/scala/skuber/PatchSpec.scala index 7f381692..e210f8c3 100644 --- a/client/src/it/scala/skuber/PatchSpec.scala +++ b/client/src/it/scala/skuber/PatchSpec.scala @@ -1,7 +1,8 @@ package skuber -import org.scalatest.{BeforeAndAfterAll, Matchers} +import org.scalatest.BeforeAndAfterAll import org.scalatest.concurrent.Eventually +import org.scalatest.matchers.should.Matchers import skuber.api.patch._ import skuber.json.format._ diff --git a/client/src/it/scala/skuber/PodDisruptionBudgetSpec.scala b/client/src/it/scala/skuber/PodDisruptionBudgetSpec.scala index 179a8b49..d9d8a833 100644 --- a/client/src/it/scala/skuber/PodDisruptionBudgetSpec.scala +++ b/client/src/it/scala/skuber/PodDisruptionBudgetSpec.scala @@ -1,6 +1,6 @@ package skuber -import org.scalatest.Matchers +import org.scalatest.matchers.should.Matchers import org.scalatest.concurrent.Eventually import skuber.apps.v1.Deployment import skuber.policy.v1beta1.PodDisruptionBudget diff --git a/client/src/it/scala/skuber/PodLogSpec.scala b/client/src/it/scala/skuber/PodLogSpec.scala index 406e8653..dd464fae 100644 --- a/client/src/it/scala/skuber/PodLogSpec.scala +++ b/client/src/it/scala/skuber/PodLogSpec.scala @@ -4,8 +4,9 @@ import java.time.ZonedDateTime import akka.stream.scaladsl.TcpIdleTimeoutException import com.typesafe.config.ConfigFactory -import org.scalatest.{BeforeAndAfterAll, Matchers} +import org.scalatest.BeforeAndAfterAll import org.scalatest.concurrent.Eventually +import org.scalatest.matchers.should.Matchers import skuber.Pod.LogQueryParams import skuber.json.format._ diff --git a/client/src/it/scala/skuber/PodSpec.scala b/client/src/it/scala/skuber/PodSpec.scala index 998b346f..d47565b3 100644 --- a/client/src/it/scala/skuber/PodSpec.scala +++ b/client/src/it/scala/skuber/PodSpec.scala @@ -1,7 +1,8 @@ package skuber -import org.scalatest.{BeforeAndAfterAll, Matchers} +import org.scalatest.BeforeAndAfterAll import org.scalatest.concurrent.Eventually +import org.scalatest.matchers.should.Matchers import skuber.json.format._ import scala.concurrent.duration._ diff --git a/client/src/it/scala/skuber/ServiceSpec.scala b/client/src/it/scala/skuber/ServiceSpec.scala index 2fb2b8f6..bb83e814 100644 --- a/client/src/it/scala/skuber/ServiceSpec.scala +++ b/client/src/it/scala/skuber/ServiceSpec.scala @@ -1,7 +1,7 @@ package skuber import skuber.json.format.serviceFmt -import org.scalatest.Matchers +import org.scalatest.matchers.should.Matchers import org.scalatest.concurrent.Eventually import scala.concurrent.Await diff --git a/client/src/it/scala/skuber/WatchContinuouslySpec.scala b/client/src/it/scala/skuber/WatchContinuouslySpec.scala index b2b9a41c..8a08befc 100644 --- a/client/src/it/scala/skuber/WatchContinuouslySpec.scala +++ b/client/src/it/scala/skuber/WatchContinuouslySpec.scala @@ -2,7 +2,7 @@ package skuber import akka.stream.KillSwitches import akka.stream.scaladsl.{Keep, Sink} -import org.scalatest.Matchers +import org.scalatest.matchers.should.Matchers import org.scalatest.concurrent.{Eventually, ScalaFutures} import org.scalatest.time.{Seconds, Span} import skuber.apps.v1.{Deployment, DeploymentList} diff --git a/client/src/main/scala/skuber/ConfigMap.scala b/client/src/main/scala/skuber/ConfigMap.scala index 8d37c613..9f6ea414 100644 --- a/client/src/main/scala/skuber/ConfigMap.scala +++ b/client/src/main/scala/skuber/ConfigMap.scala @@ -5,10 +5,13 @@ package skuber */ -case class ConfigMap(val kind: String ="ConfigMap", - override val apiVersion: String = v1, - val metadata: ObjectMeta, - data: Map[String, String] = Map()) extends ObjectResource { +case class ConfigMap( + kind: String ="ConfigMap", + apiVersion: String = v1, + metadata: ObjectMeta, + data: Map[String, String] = Map()) + extends ObjectResource +{ def withData(data: Map[String, String]): ConfigMap = this.copy(data = data) diff --git a/client/src/main/scala/skuber/Container.scala b/client/src/main/scala/skuber/Container.scala index e692adde..3d8135f1 100644 --- a/client/src/main/scala/skuber/Container.scala +++ b/client/src/main/scala/skuber/Container.scala @@ -1,37 +1,33 @@ package skuber -import java.net.URL -import java.util.Date - /** * @author David O'Riordan */ case class Container( - name: String, - image: String, - command: List[String] = List(), - args: List[String] = List(), - workingDir: Option[String] = None, - ports : List[Container.Port] = List(), - env: List[EnvVar] = List(), - resources: Option[Resource.Requirements] = None, - volumeMounts: List[Volume.Mount] = List(), - livenessProbe: Option[Probe] = None, - readinessProbe: Option[Probe] = None, - lifecycle: Option[Lifecycle] = None, - terminationMessagePath: Option[String] = None, - terminationMessagePolicy: Option[Container.TerminationMessagePolicy.Value] = None, - imagePullPolicy: Container.PullPolicy.Value = Container.PullPolicy.IfNotPresent, - securityContext: Option[SecurityContext] = None, - envFrom: List[EnvFromSource] = Nil, - stdin: Option[Boolean] = None, - stdinOnce: Option[Boolean] = None, - tty: Option[Boolean] = None, - volumeDevices: List[Volume.Device] = Nil, - startupProbe: Option[Probe] = None - ) - extends Limitable + name: String, + image: String, + command: List[String] = List(), + args: List[String] = List(), + workingDir: Option[String] = None, + ports : List[Container.Port] = List(), + env: List[EnvVar] = List(), + resources: Option[Resource.Requirements] = None, + volumeMounts: List[Volume.Mount] = List(), + livenessProbe: Option[Probe] = None, + readinessProbe: Option[Probe] = None, + lifecycle: Option[Lifecycle] = None, + terminationMessagePath: Option[String] = None, + terminationMessagePolicy: Option[Container.TerminationMessagePolicy.Value] = None, + imagePullPolicy: Container.PullPolicy.Value = Container.PullPolicy.IfNotPresent, + securityContext: Option[SecurityContext] = None, + envFrom: List[EnvFromSource] = Nil, + stdin: Option[Boolean] = None, + stdinOnce: Option[Boolean] = None, + tty: Option[Boolean] = None, + volumeDevices: List[Volume.Device] = Nil, + startupProbe: Option[Probe] = None) + extends Limitable { def exposePort(p: Container.Port) : Container = this.copy(ports=p::this.ports) def exposePort(port: Int) : Container = exposePort(Container.Port(containerPort=port)) diff --git a/client/src/main/scala/skuber/CustomResource.scala b/client/src/main/scala/skuber/CustomResource.scala index 96a249db..99c270f1 100644 --- a/client/src/main/scala/skuber/CustomResource.scala +++ b/client/src/main/scala/skuber/CustomResource.scala @@ -12,9 +12,9 @@ import scala.reflect.runtime.universe._ * pattern of being composed of "spec" and "status" subobjects. */ case class CustomResource[Sp,St]( - override val kind: String, - override val apiVersion: String, - override val metadata: ObjectMeta, + kind: String, + apiVersion: String, + metadata: ObjectMeta, spec: Sp, status: Option[St]) extends ObjectResource { diff --git a/client/src/main/scala/skuber/Endpoints.scala b/client/src/main/scala/skuber/Endpoints.scala index 65b4f28e..522d1d3c 100644 --- a/client/src/main/scala/skuber/Endpoints.scala +++ b/client/src/main/scala/skuber/Endpoints.scala @@ -4,11 +4,11 @@ package skuber * @author David O'Riordan */ case class Endpoints( - kind: String ="Endpoints", - override val apiVersion: String = v1, - metadata: ObjectMeta, - subsets: List[Endpoints.Subset] = Nil) - extends ObjectResource + kind: String ="Endpoints", + apiVersion: String = v1, + metadata: ObjectMeta, + subsets: List[Endpoints.Subset] = Nil) + extends ObjectResource { // unlikely any skuber clients will construct their own endpoints, but if so can use these fluent methods diff --git a/client/src/main/scala/skuber/EnvFromSource.scala b/client/src/main/scala/skuber/EnvFromSource.scala index 3cfa4fe4..b771e344 100644 --- a/client/src/main/scala/skuber/EnvFromSource.scala +++ b/client/src/main/scala/skuber/EnvFromSource.scala @@ -4,10 +4,7 @@ package skuber * @author David O'Riordan */ -case class EnvFromSource( - prefix: Option[String] = None, - source:EnvFromSource.EnvSource -) +case class EnvFromSource(prefix: Option[String] = None, source:EnvFromSource.EnvSource) object EnvFromSource { diff --git a/client/src/main/scala/skuber/EnvVar.scala b/client/src/main/scala/skuber/EnvVar.scala index a3951729..f6668f67 100644 --- a/client/src/main/scala/skuber/EnvVar.scala +++ b/client/src/main/scala/skuber/EnvVar.scala @@ -3,9 +3,7 @@ package skuber /** * @author David O'Riordan */ -case class EnvVar( - name: String, - value: EnvVar.Value = "") +case class EnvVar(name: String, value: EnvVar.Value = "") object EnvVar { sealed trait Value diff --git a/client/src/main/scala/skuber/Event.scala b/client/src/main/scala/skuber/Event.scala index 28c4dc6b..2e98d978 100644 --- a/client/src/main/scala/skuber/Event.scala +++ b/client/src/main/scala/skuber/Event.scala @@ -1,23 +1,20 @@ package skuber -import java.util.Date - /** * @author David O'Riordan */ case class Event( - val kind: String ="Event", - override val apiVersion: String = v1, - val metadata: ObjectMeta, - involvedObject: ObjectReference, - reason: Option[String] = None, - message: Option[String] = None, - source: Option[Event.Source] = None, - firstTimestamp: Option[Timestamp] = None, - lastTimestamp: Option[Timestamp] = None, - count: Option[Int] = None, - `type`: Option[String] = None) - extends ObjectResource + kind: String ="Event", + apiVersion: String = v1, + metadata: ObjectMeta, + involvedObject: ObjectReference, + reason: Option[String] = None, + message: Option[String] = None, + source: Option[Event.Source] = None, + firstTimestamp: Option[Timestamp] = None, + lastTimestamp: Option[Timestamp] = None, + count: Option[Int] = None, + `type`: Option[String] = None) extends ObjectResource object Event { diff --git a/client/src/main/scala/skuber/LabelSelector.scala b/client/src/main/scala/skuber/LabelSelector.scala index 7cbf55b6..55ac996d 100644 --- a/client/src/main/scala/skuber/LabelSelector.scala +++ b/client/src/main/scala/skuber/LabelSelector.scala @@ -1,12 +1,10 @@ package skuber -import java.beans.Expression - /** * @author David O'Riordan */ -case class LabelSelector(val requirements: LabelSelector.Requirement*) { +case class LabelSelector(requirements: LabelSelector.Requirement*) { override def toString=requirements.mkString(",") override def equals(o: Any) = o match { diff --git a/client/src/main/scala/skuber/LimitRange.scala b/client/src/main/scala/skuber/LimitRange.scala index d37a1b8a..18908d9b 100644 --- a/client/src/main/scala/skuber/LimitRange.scala +++ b/client/src/main/scala/skuber/LimitRange.scala @@ -5,11 +5,12 @@ package skuber * @author David O'Riordan */ case class LimitRange ( - val kind: String ="LimitRange", - override val apiVersion: String = v1, - val metadata: ObjectMeta = ObjectMeta(), - spec: Option[LimitRange.Spec] = None) - extends ObjectResource { + kind: String ="LimitRange", + apiVersion: String = v1, + metadata: ObjectMeta = ObjectMeta(), + spec: Option[LimitRange.Spec] = None) + extends ObjectResource +{ def withResourceVersion(version: String) = this.copy(metadata = metadata.copy(resourceVersion=version)) diff --git a/client/src/main/scala/skuber/Namespace.scala b/client/src/main/scala/skuber/Namespace.scala index b75e5fdb..b49b245a 100644 --- a/client/src/main/scala/skuber/Namespace.scala +++ b/client/src/main/scala/skuber/Namespace.scala @@ -1,16 +1,16 @@ package skuber - /** * @author David O'Riordan */ case class Namespace( - val kind: String ="Namespace", - override val apiVersion: String = v1, - val metadata: ObjectMeta, - spec: Option[Namespace.Spec] = None, - status: Option[Namespace.Status]= None) - extends ObjectResource { + kind: String ="Namespace", + apiVersion: String = v1, + metadata: ObjectMeta, + spec: Option[Namespace.Spec] = None, + status: Option[Namespace.Status]= None) + extends ObjectResource +{ def meta(name: String): ObjectMeta = ObjectMeta(name=name, namespace=this.name) def pod(name: String) = Pod(metadata=meta(name)) def pod(name: String, spec: Pod.Spec) = Pod(metadata=meta(name), spec=Some(spec)) diff --git a/client/src/main/scala/skuber/Node.scala b/client/src/main/scala/skuber/Node.scala index 08d8fdef..6384137e 100644 --- a/client/src/main/scala/skuber/Node.scala +++ b/client/src/main/scala/skuber/Node.scala @@ -7,12 +7,12 @@ import java.util.Date * @author David O'Riordan */ case class Node( - val kind: String ="Node", - override val apiVersion: String = v1, - val metadata: ObjectMeta, - spec: Option[Node.Spec] = None, - status: Option[Node.Status] = None) - extends ObjectResource { + kind: String ="Node", + apiVersion: String = v1, + metadata: ObjectMeta, + spec: Option[Node.Spec] = None, + status: Option[Node.Status] = None) extends ObjectResource +{ def withResourceVersion(version: String) = this.copy(metadata = metadata.copy(resourceVersion=version)) diff --git a/client/src/main/scala/skuber/PersistentVolume.scala b/client/src/main/scala/skuber/PersistentVolume.scala index e2af3162..623116cb 100644 --- a/client/src/main/scala/skuber/PersistentVolume.scala +++ b/client/src/main/scala/skuber/PersistentVolume.scala @@ -8,12 +8,13 @@ import Volume._ * @author David O'Riordan */ case class PersistentVolume( - val kind: String ="PersistentVolume", - override val apiVersion: String = v1, - val metadata: ObjectMeta = ObjectMeta(), - spec: Option[PersistentVolume.Spec] = None, - status: Option[PersistentVolume.Status] = None) - extends ObjectResource { + kind: String ="PersistentVolume", + apiVersion: String = v1, + metadata: ObjectMeta = ObjectMeta(), + spec: Option[PersistentVolume.Spec] = None, + status: Option[PersistentVolume.Status] = None) + extends ObjectResource +{ def withResourceVersion(version: String) = this.copy(metadata = metadata.copy(resourceVersion=version)) diff --git a/client/src/main/scala/skuber/PersistentVolumeClaim.scala b/client/src/main/scala/skuber/PersistentVolumeClaim.scala index f0b51a1e..18762788 100644 --- a/client/src/main/scala/skuber/PersistentVolumeClaim.scala +++ b/client/src/main/scala/skuber/PersistentVolumeClaim.scala @@ -8,12 +8,13 @@ import skuber.annotation.MatchExpression */ case class PersistentVolumeClaim( - val kind: String = "PersistentVolumeClaim", - override val apiVersion: String = v1, - val metadata: ObjectMeta = ObjectMeta(), - spec: Option[PersistentVolumeClaim.Spec] = None, - status: Option[PersistentVolumeClaim.Status] = None) - extends ObjectResource { + kind: String = "PersistentVolumeClaim", + apiVersion: String = v1, + metadata: ObjectMeta = ObjectMeta(), + spec: Option[PersistentVolumeClaim.Spec] = None, + status: Option[PersistentVolumeClaim.Status] = None) + extends ObjectResource +{ def withResourceVersion(version: String) = this.copy(metadata = metadata.copy(resourceVersion = version)) diff --git a/client/src/main/scala/skuber/Pod.scala b/client/src/main/scala/skuber/Pod.scala index daa4ae88..76a42eba 100644 --- a/client/src/main/scala/skuber/Pod.scala +++ b/client/src/main/scala/skuber/Pod.scala @@ -6,12 +6,11 @@ import java.time.format.DateTimeFormatter * @author David O'Riordan */ case class Pod( - val kind: String ="Pod", - override val apiVersion: String = v1, - val metadata: ObjectMeta, - spec: Option[Pod.Spec] = None, - status: Option[Pod.Status] = None) - extends ObjectResource with Limitable + kind: String ="Pod", + apiVersion: String = v1, + metadata: ObjectMeta, + spec: Option[Pod.Spec] = None, + status: Option[Pod.Status] = None) extends ObjectResource with Limitable object Pod { diff --git a/client/src/main/scala/skuber/Resource.scala b/client/src/main/scala/skuber/Resource.scala index 745aa35e..bcced45c 100644 --- a/client/src/main/scala/skuber/Resource.scala +++ b/client/src/main/scala/skuber/Resource.scala @@ -4,20 +4,17 @@ package skuber * @author David O'Riordan */ -import scala.math.BigDecimal - object Resource { type ResourceList=Map[String, Quantity] case class Requirements(limits: ResourceList = Map(), requests: ResourceList = Map()) case class Quota( - val kind: String = "ResourceQuota", - override val apiVersion: String = v1, - val metadata: ObjectMeta = ObjectMeta(), - spec: Option[Quota.Spec] = None, - status: Option[Quota.Status] = None) - extends ObjectResource + kind: String = "ResourceQuota", + apiVersion: String = v1, + metadata: ObjectMeta = ObjectMeta(), + spec: Option[Quota.Spec] = None, + status: Option[Quota.Status] = None) extends ObjectResource object Quota { val specification=CoreResourceSpecification( diff --git a/client/src/main/scala/skuber/ResourceDefinition.scala b/client/src/main/scala/skuber/ResourceDefinition.scala index cf3ad5a2..b829368e 100644 --- a/client/src/main/scala/skuber/ResourceDefinition.scala +++ b/client/src/main/scala/skuber/ResourceDefinition.scala @@ -1,10 +1,7 @@ package skuber -import play.api.libs.json.{Format, Json} import skuber.apiextensions.CustomResourceDefinition -import scala.reflect.runtime.universe._ - /** * @author David O'Riordan * @@ -58,9 +55,9 @@ object ResourceDefinition { /** * This will provide an implicit resource definition require by API `list` methods, as long as an implicit resource * definition for the corresponding object resource type is in scope - * @param rd - * @tparam O - * @return + * @param rd resource definition for the object resource kind + * @tparam O the object resource type + * @return an implicit resource definition for the list resource kind */ implicit def listDef[O <: ObjectResource](implicit rd: ResourceDefinition[O]): ResourceDefinition[ListResource[O]] = { new ResourceDefinition[ListResource[O]] { diff --git a/client/src/main/scala/skuber/ResourceSpecification.scala b/client/src/main/scala/skuber/ResourceSpecification.scala index 211d43de..0a72ac44 100644 --- a/client/src/main/scala/skuber/ResourceSpecification.scala +++ b/client/src/main/scala/skuber/ResourceSpecification.scala @@ -77,12 +77,12 @@ case class CoreResourceSpecification( * NonCoreResourceSpecification is used to specify any resource types outside the core k8s API group, including custom resources */ case class NonCoreResourceSpecification( - val apiGroup: String, - val version: Option[String], - val versions: List[ResourceSpecification.Version], // introduced in k8s v1.11 for CRD types - override val scope: ResourceSpecification.Scope.Value, - override val names: ResourceSpecification.Names, - override val subresources: Option[ResourceSpecification.Subresources] = None) extends ResourceSpecification + apiGroup: String, + version: Option[String], + versions: List[ResourceSpecification.Version], // introduced in k8s v1.11 for CRD types + scope: ResourceSpecification.Scope.Value, + names: ResourceSpecification.Names, + subresources: Option[ResourceSpecification.Subresources] = None) extends ResourceSpecification { def apiPathPrefix="apis" override def group: Option[String] = Some(apiGroup) diff --git a/client/src/main/scala/skuber/Scale.scala b/client/src/main/scala/skuber/Scale.scala index 720cb8ab..f28397ff 100644 --- a/client/src/main/scala/skuber/Scale.scala +++ b/client/src/main/scala/skuber/Scale.scala @@ -2,18 +2,19 @@ package skuber import play.api.libs.functional.syntax._ import play.api.libs.json.{Format, JsPath, Json} -import skuber.json.format.{maybeEmptyFormatMethods,jsPath2LabelSelFormat,objectMetaFormat} +import skuber.json.format.{maybeEmptyFormatMethods,jsPath2LabelSelFormat, objectMetaFormat} /** * @author David O'Riordan * Scale subresource */ case class Scale( - val kind: String = "Scale", - val apiVersion: String, - val metadata: ObjectMeta, - spec: Scale.Spec = Scale.Spec(), - status: Option[Scale.Status] = None) extends ObjectResource + kind: String = "Scale", + apiVersion: String, + metadata: ObjectMeta, + spec: Scale.Spec = Scale.Spec(), + status: Option[Scale.Status] = None) + extends ObjectResource { def withSpecReplicas(count: Int) = this.copy(spec=Scale.Spec(Some(count))) def withStatusReplicas(count: Int) = { diff --git a/client/src/main/scala/skuber/Secret.scala b/client/src/main/scala/skuber/Secret.scala index beefe5c9..c28c9a35 100644 --- a/client/src/main/scala/skuber/Secret.scala +++ b/client/src/main/scala/skuber/Secret.scala @@ -7,12 +7,13 @@ import org.apache.commons.io.IOUtils * @author David O'Riordan */ case class Secret( - val kind: String ="Secret", - override val apiVersion: String = v1, - val metadata: ObjectMeta, + kind: String ="Secret", + apiVersion: String = v1, + metadata: ObjectMeta, data: Map[String, Array[Byte]] = Map(), - val `type`: String = "") - extends ObjectResource { + `type`: String = "") + extends ObjectResource +{ def add(key: String, is: InputStream) : Secret = { val bytes = IOUtils.toByteArray(is) diff --git a/client/src/main/scala/skuber/Security.scala b/client/src/main/scala/skuber/Security.scala index d870ebf0..2d24f981 100644 --- a/client/src/main/scala/skuber/Security.scala +++ b/client/src/main/scala/skuber/Security.scala @@ -7,42 +7,33 @@ package skuber import Security._ case class SecurityContext( - allowPrivilegeEscalation: Option[Boolean] = None, - capabilities: Option[Capabilities] = None, - privileged: Option[Boolean] = None, - readOnlyRootFilesystem: Option[Boolean] = None, - runAsGroup: Option[Int] = None, - runAsNonRoot: Option[Boolean] = None, - runAsUser: Option[Int] = None, - seLinuxOptions: Option[SELinuxOptions] = None - ) + allowPrivilegeEscalation: Option[Boolean] = None, + capabilities: Option[Capabilities] = None, + privileged: Option[Boolean] = None, + readOnlyRootFilesystem: Option[Boolean] = None, + runAsGroup: Option[Int] = None, + runAsNonRoot: Option[Boolean] = None, + runAsUser: Option[Int] = None, + seLinuxOptions: Option[SELinuxOptions] = None +) case class PodSecurityContext( - fsGroup: Option[Int] = None, - runAsGroup: Option[Int] = None, - runAsNonRoot: Option[Boolean] = None, - runAsUser: Option[Int] = None, - seLinuxOptions: Option[SELinuxOptions] = None, - supplementalGroups: List[Int] = Nil, - sysctls: List[Sysctl] = Nil - ) + fsGroup: Option[Int] = None, + runAsGroup: Option[Int] = None, + runAsNonRoot: Option[Boolean] = None, + runAsUser: Option[Int] = None, + seLinuxOptions: Option[SELinuxOptions] = None, + supplementalGroups: List[Int] = Nil, + sysctls: List[Sysctl] = Nil +) object Security { type Capability = String - case class Capabilities( - add: List[Capability] = Nil, - drop: List[Capability] = Nil) + case class Capabilities(add: List[Capability] = Nil, drop: List[Capability] = Nil) - case class SELinuxOptions( - user: String = "", - role: String = "", - _type: String = "", - level: String = "") + case class SELinuxOptions(user: String = "", role: String = "", _type: String = "", level: String = "") - case class Sysctl( - name: String, - value: String - ) + case class Sysctl(name: String, value: String) } \ No newline at end of file diff --git a/client/src/main/scala/skuber/ServiceAccount.scala b/client/src/main/scala/skuber/ServiceAccount.scala index 4ccaca54..17656d09 100644 --- a/client/src/main/scala/skuber/ServiceAccount.scala +++ b/client/src/main/scala/skuber/ServiceAccount.scala @@ -4,12 +4,13 @@ package skuber * @author David O'Riordan */ case class ServiceAccount( - val kind: String ="ServiceAccount", - override val apiVersion: String = "v1", - val metadata: ObjectMeta, + kind: String ="ServiceAccount", + apiVersion: String = "v1", + metadata: ObjectMeta, secrets: List[ObjectReference] = List(), imagePullSecrets: List[LocalObjectReference] = List()) - extends ObjectResource { + extends ObjectResource +{ def withResourceVersion(version: String) = this.copy(metadata = metadata.copy(resourceVersion=version)) } diff --git a/client/src/main/scala/skuber/annotation/NodeAffinity.scala b/client/src/main/scala/skuber/annotation/NodeAffinity.scala index cca12b59..d914d3f9 100644 --- a/client/src/main/scala/skuber/annotation/NodeAffinity.scala +++ b/client/src/main/scala/skuber/annotation/NodeAffinity.scala @@ -9,9 +9,9 @@ import skuber.annotation.NodeAffinity.{MatchExpressions, NodeSelectorTerms} * Kubernetes 1.6 or later. It should be set directly in the Pod.Spec (see PodFormatSpec for an example) */ case class NodeAffinity( - requiredDuringSchedulingIgnoredDuringExecution: Option[RequiredDuringSchedulingIgnoredDuringExecution], - preferredDuringSchedulingIgnoredDuringExecution: Option[PreferredDuringSchedulingIgnoredDuringExecution] - ) + requiredDuringSchedulingIgnoredDuringExecution: Option[RequiredDuringSchedulingIgnoredDuringExecution], + preferredDuringSchedulingIgnoredDuringExecution: Option[PreferredDuringSchedulingIgnoredDuringExecution] +) object NodeAffinity { val ANNOTATION_NAME = "scheduler.alpha.kubernetes.io/affinity" diff --git a/client/src/main/scala/skuber/api/Configuration.scala b/client/src/main/scala/skuber/api/Configuration.scala index e5bbbd06..d44567d0 100644 --- a/client/src/main/scala/skuber/api/Configuration.scala +++ b/client/src/main/scala/skuber/api/Configuration.scala @@ -1,6 +1,5 @@ package skuber.api -import java.io.File import java.net.URL import java.time.Instant import java.time.format.DateTimeFormatter @@ -25,11 +24,14 @@ case class Configuration( currentContext: Context = Context(), users: Map[String, AuthInfo] = Map()) { - def withCluster(name:String, cluster: Cluster) = this.copy(clusters = this.clusters + (name -> cluster)) - def withContext(name: String, context: Context) = this.copy(contexts = this.contexts + (name -> context)) - def useContext(context: Context) = this.copy(currentContext=context) - def setCurrentNamespace(namespaceName: String) = - this.copy(currentContext=this.currentContext.copy(namespace=Namespace.forName(namespaceName))) + def withCluster(name: String, cluster: Cluster): Configuration = this.copy(clusters = this.clusters + (name -> cluster)) + + def withContext(name: String, context: Context): Configuration = this.copy(contexts = this.contexts + (name -> context)) + + def useContext(context: Context): Configuration = this.copy(currentContext = context) + + def setCurrentNamespace(namespaceName: String): Configuration = + this.copy(currentContext = this.currentContext.copy(namespace = Namespace.forName(namespaceName))) } @@ -134,7 +136,7 @@ object Configuration { // Note - implication is that a data setting overrides a path setting (path, data) match { case (_, Some(b64EncodedData)) => Some(Right(Base64.getDecoder.decode(b64EncodedData))) - case (Some(p), _) => { + case (Some(p), _) => // path specified // if it is a relative path and a directory was specified then construct full path from those components, // otherwise just return path as given @@ -144,7 +146,6 @@ object Configuration { case _ => p } Some(Left(expandedPath)) - } case (None, None) => None } } @@ -208,10 +209,10 @@ object Configuration { val k8sAuthInfoMap = topLevelYamlToK8SConfigMap("user", toK8SAuthInfo) def toK8SContext(contextConfig: YamlMap) = { - val cluster=contextConfig.asScala.get("cluster").filterNot(_ == "").map { clusterName => + val cluster=contextConfig.asScala.get("cluster").filterNot(_.asInstanceOf[String] == "").map { clusterName => k8sClusterMap.get(clusterName.asInstanceOf[String]).get }.getOrElse(Cluster()) - val authInfo =contextConfig.asScala.get("user").filterNot(_ == "").map { userKey => + val authInfo =contextConfig.asScala.get("user").filterNot(_.asInstanceOf[String] == "").map { userKey => k8sAuthInfoMap.get(userKey.asInstanceOf[String]).get }.getOrElse(NoAuth) val namespace=contextConfig.asScala.get("namespace").fold(Namespace.default) { name=>Namespace.forName(name.asInstanceOf[String]) } @@ -265,7 +266,7 @@ object Configuration { port <- maybePort token <- maybeToken namespace <- maybeNamespace - hostPort = s"https://$host${if (port.length > 0) ":" + port else ""}" + hostPort = s"https://$host${if (port.nonEmpty) ":" + port else ""}" cluster = Cluster(server = hostPort, certificateAuthority = ca) ctx = Context(cluster, TokenAuth(token), Namespace.forName(namespace)) } yield Configuration( @@ -278,7 +279,7 @@ object Configuration { /* * Get the current default configuration */ - def defaultK8sConfig = { + def defaultK8sConfig: Configuration = { import java.nio.file.Paths val skuberUrlOverride = sys.env.get("SKUBER_URL") diff --git a/client/src/main/scala/skuber/api/client/KubernetesClient.scala b/client/src/main/scala/skuber/api/client/KubernetesClient.scala index 92d7708e..7a8e0854 100644 --- a/client/src/main/scala/skuber/api/client/KubernetesClient.scala +++ b/client/src/main/scala/skuber/api/client/KubernetesClient.scala @@ -352,7 +352,7 @@ trait KubernetesClient { /** * Return list of API versions supported by the server - * @param lc + * @param lc logging context * @return a future containing the list of API versions */ def getServerAPIVersions(implicit lc: LoggingContext): Future[List[String]] @@ -361,15 +361,15 @@ trait KubernetesClient { * Create a new KubernetesClient instance that reuses this clients configuration and connection resources, but with a different * target namespace. * This is useful for applications that need a lightweight way to target multiple or dynamic namespaces. - * @param newNamespace - * @return + * @param newNamespace target namespace + * @return the new client instance */ def usingNamespace(newNamespace: String): KubernetesClient /** * Closes the client. Any requests to the client after this is called will be rejected. */ - def close: Unit + def close(): Unit // Some parameters of the client that it may be useful for some applications to read val logConfig: LoggingConfig // the logging configuration for client requests diff --git a/client/src/main/scala/skuber/api/client/LoggingConfig.scala b/client/src/main/scala/skuber/api/client/LoggingConfig.scala index cd31ad0e..7406dbf0 100644 --- a/client/src/main/scala/skuber/api/client/LoggingConfig.scala +++ b/client/src/main/scala/skuber/api/client/LoggingConfig.scala @@ -9,16 +9,16 @@ import LoggingConfig.loggingEnabled import scala.util.{Failure, Success, Try} case class LoggingConfig( - logConfiguration: Boolean=loggingEnabled("config", true), // outputs configuration on initialisation) - logRequestBasic: Boolean=loggingEnabled("request", true), // logs method and URL for request - logRequestBasicMetadata: Boolean=loggingEnabled("request.metadata", false), // logs key resource metadata information if available - logRequestFullObjectResource: Boolean=loggingEnabled("request.object.full", false), // outputs full object resource if available - logResponseBasic: Boolean=loggingEnabled("response", true), // logs basic response info (status code) - logResponseBasicMetadata: Boolean=loggingEnabled("response.metadata", false), // logs some basic metadata from the returned resource, if available - logResponseFullObjectResource: Boolean=loggingEnabled("response.object.full", false), // outputs full received object resource, if available - logResponseListSize: Boolean=loggingEnabled("response.list.size", false), // logs size of any returned list resource - logResponseListNames: Boolean=loggingEnabled("response.list.names", false), // logs list of names of items in any returned list resource - logResponseFullListResource: Boolean= loggingEnabled("response.list.full", false) // outputs full contained object resources in list resources + logConfiguration: Boolean=loggingEnabled("config", fallback = true), // outputs configuration on initialisation) + logRequestBasic: Boolean=loggingEnabled("request", fallback = true), // logs method and URL for request + logRequestBasicMetadata: Boolean=loggingEnabled("request.metadata", fallback = false), // logs key resource metadata information if available + logRequestFullObjectResource: Boolean=loggingEnabled("request.object.full", fallback = false), // outputs full object resource if available + logResponseBasic: Boolean=loggingEnabled("response", fallback = true), // logs basic response info (status code) + logResponseBasicMetadata: Boolean=loggingEnabled("response.metadata", fallback = false), // logs some basic metadata from the returned resource, if available + logResponseFullObjectResource: Boolean=loggingEnabled("response.object.full", fallback = false), // outputs full received object resource, if available + logResponseListSize: Boolean=loggingEnabled("response.list.size", fallback = false), // logs size of any returned list resource + logResponseListNames: Boolean=loggingEnabled("response.list.names", fallback = false), // logs list of names of items in any returned list resource + logResponseFullListResource: Boolean= loggingEnabled("response.list.full", fallback = false) // outputs full contained object resources in list resources ) object LoggingConfig { diff --git a/client/src/main/scala/skuber/api/client/exec/PodExecImpl.scala b/client/src/main/scala/skuber/api/client/exec/PodExecImpl.scala index 86c23d3f..6e0dbe75 100644 --- a/client/src/main/scala/skuber/api/client/exec/PodExecImpl.scala +++ b/client/src/main/scala/skuber/api/client/exec/PodExecImpl.scala @@ -5,7 +5,7 @@ import akka.http.scaladsl.model.headers.RawHeader import akka.http.scaladsl.model.{HttpHeader, StatusCodes, Uri, ws} import akka.http.scaladsl.{ConnectionContext, Http} import akka.stream.scaladsl.{Flow, GraphDSL, Keep, Partition, Sink, Source} -import akka.stream.{Materializer, SinkShape} +import akka.stream.SinkShape import akka.util.ByteString import akka.{Done, NotUsed} import skuber.api.client.impl.KubernetesClientImpl @@ -34,7 +34,7 @@ object PodExecImpl { implicit val executor: ExecutionContext = sys.dispatcher val containerPrintName = maybeContainerName.getOrElse("") - requestContext.log.info(s"Trying to connect to container ${containerPrintName} of pod ${podName}") + requestContext.log.info(s"Trying to connect to container $containerPrintName of pod $podName") // Compose queries var queries: Seq[(String, String)] = Seq( @@ -51,7 +51,7 @@ object PodExecImpl { // Determine scheme and connection context based on SSL context val (scheme, connectionContext) = requestContext.sslContext match { case Some(ssl) => - ("wss",ConnectionContext.https(ssl, enabledProtocols = Some(scala.collection.immutable.Seq("TLSv1.2", "TLSv1")))) + ("wss",ConnectionContext.httpsClient(ssl)) case None => ("ws", Http().defaultClientHttpsContext) } @@ -59,7 +59,7 @@ object PodExecImpl { // Compose URI val uri = Uri(requestContext.clusterServer) .withScheme(scheme) - .withPath(Uri.Path(s"/api/v1/namespaces/${requestContext.namespaceName}/pods/${podName}/exec")) + .withPath(Uri.Path(s"/api/v1/namespaces/${requestContext.namespaceName}/pods/$podName/exec")) .withQuery(Uri.Query(queries: _*)) // Compose headers @@ -116,9 +116,9 @@ object PodExecImpl { val close = maybeClose.getOrElse(Promise.successful(())) connected.foreach { _ => - requestContext.log.info(s"Connected to container ${containerPrintName} of pod ${podName}") + requestContext.log.info(s"Connected to container $containerPrintName of pod $podName") close.future.foreach { _ => - requestContext.log.info(s"Close the connection of container ${containerPrintName} of pod ${podName}") + requestContext.log.info(s"Close the connection of container $containerPrintName of pod $podName") promise.success(None) } } diff --git a/client/src/main/scala/skuber/api/client/impl/KubernetesClientImpl.scala b/client/src/main/scala/skuber/api/client/impl/KubernetesClientImpl.scala index 025ec060..7e7e8bd7 100644 --- a/client/src/main/scala/skuber/api/client/impl/KubernetesClientImpl.scala +++ b/client/src/main/scala/skuber/api/client/impl/KubernetesClientImpl.scala @@ -6,8 +6,7 @@ import akka.http.scaladsl.marshalling.Marshal import akka.http.scaladsl.model._ import akka.http.scaladsl.settings.{ClientConnectionSettings, ConnectionPoolSettings} import akka.http.scaladsl.unmarshalling.Unmarshal -import akka.http.scaladsl.{ConnectionContext, Http, HttpsConnectionContext} -import akka.stream.Materializer +import akka.http.scaladsl.{ConnectionContext, Http} import akka.stream.scaladsl.{Sink, Source} import akka.util.ByteString import com.typesafe.config.{Config, ConfigFactory} @@ -52,7 +51,7 @@ class KubernetesClientImpl private[client] ( val connectionContext = sslContext .map { ssl => - ConnectionContext.https(ssl, enabledProtocols = Some(scala.collection.immutable.Seq("TLSv1.2", "TLSv1"))) + ConnectionContext.httpsClient(ssl) } .getOrElse(Http().defaultClientHttpsContext) @@ -119,7 +118,7 @@ class KubernetesClientImpl private[client] ( private[skuber] def logInfo(enabledLogEvent: Boolean, msg: => String)(implicit lc: LoggingContext) = { if (log.isInfoEnabled && enabledLogEvent) { - log.info(s"[ ${lc.output} - ${msg}]") + log.info(s"[ ${lc.output} - $msg]") } } @@ -127,7 +126,7 @@ class KubernetesClientImpl private[client] ( { if (log.isInfoEnabled && enabledLogEvent) { msgOpt foreach { msg => - log.info(s"[ ${lc.output} - ${msg}]") + log.info(s"[ ${lc.output} - $msg]") } } } @@ -513,7 +512,7 @@ class KubernetesClientImpl private[client] ( clusterServerUri.authority.host.address(), clusterServerUri.effectivePort, watchPoolIdleTimeout, - sslContext.map(new HttpsConnectionContext(_)), + sslContext.map(ConnectionContext.httpsClient(_)), ClientConnectionSettings(actorSystem.settings.config).withIdleTimeout(watchContinuouslyIdleTimeout) ) } @@ -622,7 +621,7 @@ class KubernetesClientImpl private[client] ( PodExecImpl.exec(this, podName, command, maybeContainerName, maybeStdin, maybeStdout, maybeStderr, tty, maybeClose) } - override def close: Unit = + override def close(): Unit = { isClosed = true closeHook foreach { diff --git a/client/src/main/scala/skuber/api/client/package.scala b/client/src/main/scala/skuber/api/client/package.scala index d66a2977..48d7242b 100644 --- a/client/src/main/scala/skuber/api/client/package.scala +++ b/client/src/main/scala/skuber/api/client/package.scala @@ -6,7 +6,6 @@ import java.util.UUID import akka.NotUsed import akka.actor.ActorSystem import akka.http.scaladsl.model._ -import akka.stream.Materializer import akka.stream.scaladsl.Flow import com.typesafe.config.{Config, ConfigFactory} import play.api.libs.functional.syntax._ @@ -15,7 +14,7 @@ import play.api.libs.json._ import scala.sys.SystemProperties import scala.util.Try -import skuber.{LabelSelector, ObjectResource} +import skuber.ObjectResource import skuber.api.client.impl.KubernetesClientImpl /** @@ -59,7 +58,7 @@ package object client { } final case class CertAuth(clientCertificate: PathOrData, clientKey: PathOrData, user: Option[String]) extends AuthInfo { - override def toString: String = StringBuilder.newBuilder + override def toString: String = new StringBuilder() .append(getClass.getSimpleName) .append("(") .append { @@ -117,7 +116,7 @@ package object client { } } - override def toString = + override def toString: String = """GcpAuth(accessToken=)""".stripMargin } diff --git a/client/src/main/scala/skuber/api/patch.scala b/client/src/main/scala/skuber/api/patch.scala index 7ab15216..5ec3b861 100644 --- a/client/src/main/scala/skuber/api/patch.scala +++ b/client/src/main/scala/skuber/api/patch.scala @@ -6,8 +6,8 @@ import play.api.libs.json.Writes package object patch { object CustomMediaTypes { - val `application/merge-patch+json` = MediaType.applicationWithFixedCharset("merge-patch+json", HttpCharsets.`UTF-8`) - val `application/strategic-merge-patch+json` = MediaType.applicationWithFixedCharset("strategic-merge-patch+json", HttpCharsets.`UTF-8`) + val `application/merge-patch+json`: MediaType.WithFixedCharset = MediaType.applicationWithFixedCharset("merge-patch+json", HttpCharsets.`UTF-8`) + val `application/strategic-merge-patch+json`: MediaType.WithFixedCharset = MediaType.applicationWithFixedCharset("strategic-merge-patch+json", HttpCharsets.`UTF-8`) } object JsonPatchOperation { diff --git a/client/src/main/scala/skuber/api/security/SecurityHelper.scala b/client/src/main/scala/skuber/api/security/SecurityHelper.scala index 65536779..f59da6d1 100644 --- a/client/src/main/scala/skuber/api/security/SecurityHelper.scala +++ b/client/src/main/scala/skuber/api/security/SecurityHelper.scala @@ -7,15 +7,11 @@ import java.nio.file.{Files, Paths} import java.security.{KeyStore, PrivateKey} import java.security.cert.{CertificateFactory, X509Certificate} import java.security.KeyFactory -import java.security.InvalidKeyException import java.security.spec.PKCS8EncodedKeySpec import scala.io.Source import scala.collection.JavaConverters._ import skuber.api.client.PathOrData -import skuber.api.security.SecurityHelper.PKCS8ECPrivateKeyParser.getPKCS8PrivateKey -import skuber.api.security.SecurityHelper.PrivateKeyParser -import java.nio.charset.StandardCharsets import scala.util.{Success, Try} /** @@ -35,10 +31,9 @@ object SecurityHelper { private def createInputStreamForPathOrData(target: PathOrData) : InputStream = { target match { case Right(data) => new ByteArrayInputStream(data) - case Left(path) => { + case Left(path) => val filePath = Paths.get(path) Files.newInputStream(filePath) - } } } @@ -94,14 +89,14 @@ object SecurityHelper { * @param header The expected PEM header for the key type * @param footer The expected PEM footer for the key type */ - case class PEMHeaderFooter(val header: String, val footer: String) + case class PEMHeaderFooter(header: String, footer: String) - val pkcs1PrivateKeyHdrFooter = - PEMHeaderFooter("-----BEGIN RSA PRIVATE KEY-----","-----END RSA PRIVATE KEY-----") - val pkcs8PrivateKeyHdrFooter = + val pkcs1PrivateKeyHdrFooter: PEMHeaderFooter = + PEMHeaderFooter("-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----") + val pkcs8PrivateKeyHdrFooter: PEMHeaderFooter = PEMHeaderFooter("-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----") // openssl may generate following header/footer specifically for EC case - val pkcs8ECPrivateKeyHdrFooter = + val pkcs8ECPrivateKeyHdrFooter: PEMHeaderFooter = PEMHeaderFooter("-----BEGIN EC PRIVATE KEY-----", "-----END EC PRIVATE KEY-----") trait PrivateKeyParser @@ -122,8 +117,8 @@ object SecurityHelper { override val headerFooter: PEMHeaderFooter = pkcs1PrivateKeyHdrFooter override def getPrivateKey(keyBytes: Array[Byte]): PrivateKey = { // java security API does not support pkcs#1 so convert to pkcs#8 RSA first - val pkcs1Length = keyBytes.length; - val totalLength = pkcs1Length + 22; + val pkcs1Length = keyBytes.length + val totalLength = pkcs1Length + 22 val pkcs8Header: Array[Byte] = Array[Byte]( 0x30.toByte, 0x82.toByte, ((totalLength >> 8) & 0xff).toByte, (totalLength & 0xff).toByte, // Sequence + total length 0x2.toByte, 0x1.toByte, 0x0.toByte, // Integer (0) @@ -156,7 +151,7 @@ object SecurityHelper { override def getPrivateKey(keyBytes: Array[Byte]): PrivateKey = getPKCS8PrivateKey(keyBytes, "EC") } - val privateKeyParsers = List(PKCS1PrivateKeyParser,PKCS8PrivateKeyParser,PKCS8ECPrivateKeyParser) + private val privateKeyParsers: List[PrivateKeyParser] = List(PKCS1PrivateKeyParser, PKCS8PrivateKeyParser, PKCS8ECPrivateKeyParser) private def findPrivateKeyParser(pemData: String): Option[PrivateKeyParser] = { privateKeyParsers.find { parser => diff --git a/client/src/main/scala/skuber/api/watch/LongPollingPool.scala b/client/src/main/scala/skuber/api/watch/LongPollingPool.scala index ed31ca37..19d9fa81 100644 --- a/client/src/main/scala/skuber/api/watch/LongPollingPool.scala +++ b/client/src/main/scala/skuber/api/watch/LongPollingPool.scala @@ -4,7 +4,6 @@ import akka.NotUsed import akka.actor.ActorSystem import akka.http.scaladsl.settings.{ClientConnectionSettings, ConnectionPoolSettings} import akka.http.scaladsl.{Http, HttpsConnectionContext} -import akka.stream.Materializer import skuber.api.client.Pool import scala.concurrent.duration._ @@ -31,7 +30,7 @@ private[api] object LongPollingPool { } } - private def buildHostConnectionPool[T](poolIdleTimeout: Duration, clientConnectionSettings: ClientConnectionSettings, system: ActorSystem) = { + private def buildHostConnectionPool(poolIdleTimeout: Duration, clientConnectionSettings: ClientConnectionSettings, system: ActorSystem) = { ConnectionPoolSettings(system) .withMaxConnections(1) // Limit number the of open connections to one .withPipeliningLimit(1) // Limit pipelining of requests to one diff --git a/client/src/main/scala/skuber/api/watch/Watch.scala b/client/src/main/scala/skuber/api/watch/Watch.scala index 7a5c7d13..85c37e57 100644 --- a/client/src/main/scala/skuber/api/watch/Watch.scala +++ b/client/src/main/scala/skuber/api/watch/Watch.scala @@ -18,14 +18,14 @@ import scala.language.postfixOps object Watch { /** - * Get a source of events on a specific Kubernetes resource + * Get a source of events on a specific Kubernetes resource type * @param context the applicable request context * @param name the name of the Kubernetes resource to watch * @param sinceResourceVersion if specfied all events since the resource version are included, otherwise only future events * @param bufSize maximum size of each event in the event stream, in bytes - * @param format - * @param rd - * @tparam O + * @param format the json formatter for the object resource type + * @param rd the resource definition for the object resource type + * @tparam O the object resource type * @return */ def events[O <: ObjectResource](context: KubernetesClientImpl, name: String, sinceResourceVersion: Option[String] = None, bufSize: Int)( @@ -45,13 +45,13 @@ object Watch { } /** - * Get a source of events on all resources of a specified kind + * Get a source of events on all resources of a specified object resource type * @param context the applicable request context * @param sinceResourceVersion if specfied all events since the resource version are included, otherwise only future events * @param bufSize maximum size of each event in the event stream, in bytes * @param format Play json formatter for the applicable Kubernetes type, used to read each event object * @param rd resource definition for the kind, required for building the watch request Uri. - * @tparam O + * @tparam O the object resource type * @return a Future which will eventually return a Source of events */ def eventsOnKind[O <: ObjectResource](context: KubernetesClientImpl, sinceResourceVersion: Option[String] = None, bufSize: Int)( diff --git a/client/src/main/scala/skuber/apiextensions/CustomResourceDefinition.scala b/client/src/main/scala/skuber/apiextensions/CustomResourceDefinition.scala index a7703f70..9bf0239d 100644 --- a/client/src/main/scala/skuber/apiextensions/CustomResourceDefinition.scala +++ b/client/src/main/scala/skuber/apiextensions/CustomResourceDefinition.scala @@ -1,6 +1,5 @@ package skuber.apiextensions -import play.api.libs.functional.syntax.unlift import play.api.libs.json.{JsPath, JsResult, JsSuccess, JsValue} import skuber.ResourceSpecification.StatusSubresource import skuber.{NonCoreResourceSpecification, ObjectEditor, ObjectMeta, ObjectResource, ResourceDefinition, ResourceSpecification, TypeMeta} @@ -9,11 +8,10 @@ import skuber.{NonCoreResourceSpecification, ObjectEditor, ObjectMeta, ObjectRes * @author David O'Riordan */ case class CustomResourceDefinition( - val kind: String = "CustomResourceDefinition", + kind: String = "CustomResourceDefinition", override val apiVersion: String = "apiextensions.k8s.io/v1beta1", - val metadata: ObjectMeta, + metadata: ObjectMeta, spec: CustomResourceDefinition.Spec - ) extends ObjectResource object CustomResourceDefinition { @@ -87,7 +85,7 @@ object CustomResourceDefinition { val crdSpec: Spec = try { implicitly[ResourceDefinition[T]].spec.asInstanceOf[Spec] } catch { - case ex: ClassCastException => + case _: ClassCastException => val msg = "Requires an implicit resource definition that has a NonCoreResourceSpecification" throw new skuber.K8SException(skuber.api.client.Status(message = Some(msg))) } diff --git a/client/src/main/scala/skuber/apps/Deployment.scala b/client/src/main/scala/skuber/apps/Deployment.scala index d644df08..4b4f3516 100644 --- a/client/src/main/scala/skuber/apps/Deployment.scala +++ b/client/src/main/scala/skuber/apps/Deployment.scala @@ -9,7 +9,7 @@ import skuber._ case class Deployment( kind: String ="Deployment", - override val apiVersion: String = "apps/v1beta1", + apiVersion: String = "apps/v1beta1", metadata: ObjectMeta = ObjectMeta(), spec: Option[Deployment.Spec] = None, status: Option[Deployment.Status] = None) diff --git a/client/src/main/scala/skuber/apps/StatefulSet.scala b/client/src/main/scala/skuber/apps/StatefulSet.scala index 3f1d1765..a63c4059 100644 --- a/client/src/main/scala/skuber/apps/StatefulSet.scala +++ b/client/src/main/scala/skuber/apps/StatefulSet.scala @@ -12,15 +12,17 @@ import skuber.json.format._ // reuse some core skuber json formatters * The api version of this StatefulSet type is v1beta2, which is for use with k8s 1.8+. * For earlier versions of k8s, use skuber.apps.v1beta1.StatefulSet */ -case class StatefulSet(override val kind: String ="StatefulSet", - override val apiVersion: String = "apps/v1beta2", // correct at k8s 1.8 - metadata: ObjectMeta, - spec: Option[StatefulSet.Spec] = None, - status: Option[StatefulSet.Status] = None) extends ObjectResource +case class StatefulSet( + kind: String ="StatefulSet", + apiVersion: String = "apps/v1beta2", // correct at k8s 1.8 + metadata: ObjectMeta, + spec: Option[StatefulSet.Spec] = None, + status: Option[StatefulSet.Status] = None) + extends ObjectResource { def withResourceVersion(version: String) = this.copy(metadata = metadata.copy(resourceVersion=version)) - lazy val copySpec = this.spec.getOrElse(new StatefulSet.Spec(template = Pod.Template.Spec())) + lazy val copySpec = this.spec.getOrElse(StatefulSet.Spec(template = Pod.Template.Spec())) private val rollingUpdateStrategy = StatefulSet.UpdateStrategy(`type`=StatefulSet.UpdateStrategyType.RollingUpdate, None) private def rollingUpdateStrategy(partition: Int)= StatefulSet.UpdateStrategy(`type`=StatefulSet.UpdateStrategyType.RollingUpdate,Some(StatefulSet.RollingUpdateStrategy(partition))) diff --git a/client/src/main/scala/skuber/apps/v1/DaemonSet.scala b/client/src/main/scala/skuber/apps/v1/DaemonSet.scala index c82bd887..1ca76bb4 100644 --- a/client/src/main/scala/skuber/apps/v1/DaemonSet.scala +++ b/client/src/main/scala/skuber/apps/v1/DaemonSet.scala @@ -7,13 +7,14 @@ package skuber.apps.v1 import skuber.ResourceSpecification.{Names, Scope} import skuber.{IntOrString, LabelSelector, NonCoreResourceSpecification, ObjectMeta, ObjectResource, Pod, ResourceDefinition, Timestamp} -case class DaemonSet(val kind: String ="DaemonSet", - override val apiVersion: String = appsAPIVersion, - val metadata: ObjectMeta, +case class DaemonSet( + kind: String ="DaemonSet", + apiVersion: String = appsAPIVersion, + metadata: ObjectMeta, spec: Option[DaemonSet.Spec] = None, status: Option[DaemonSet.Status] = None) - extends ObjectResource { - + extends ObjectResource +{ lazy val copySpec = this.spec.getOrElse(new DaemonSet.Spec) def withTemplate(template: Pod.Template.Spec) = this.copy(spec=Some(copySpec.copy(template=Some(template)))) @@ -92,9 +93,8 @@ object DaemonSet { import skuber.json.format._ implicit val condFmt: Format[Condition] = Json.format[Condition] - implicit val rollingUpdFmt: Format[RollingUpdate] = ( + implicit val rollingUpdFmt: Format[RollingUpdate] = (JsPath \ "maxUnavailable").formatMaybeEmptyIntOrString(Left(1)).inmap(mu => RollingUpdate(mu), (ru: RollingUpdate) => ru.maxUnavailable) - ) implicit val updateStrategyFmt: Format[UpdateStrategy] = ( (JsPath \ "type").formatEnum(UpdateStrategyType, Some(UpdateStrategyType.RollingUpdate)) and diff --git a/client/src/main/scala/skuber/apps/v1/Deployment.scala b/client/src/main/scala/skuber/apps/v1/Deployment.scala index 3a408aac..f144a3c4 100644 --- a/client/src/main/scala/skuber/apps/v1/Deployment.scala +++ b/client/src/main/scala/skuber/apps/v1/Deployment.scala @@ -4,21 +4,20 @@ package skuber.apps.v1 * @author David O'Riordan */ -import skuber.LabelSelector.IsEqualRequirement import skuber.ResourceSpecification.{Names, Scope} import skuber._ case class Deployment( - val kind: String ="Deployment", - override val apiVersion: String = appsAPIVersion, - val metadata: ObjectMeta = ObjectMeta(), - val spec: Option[Deployment.Spec] = None, - val status: Option[Deployment.Status] = None) + kind: String ="Deployment", + apiVersion: String = appsAPIVersion, + metadata: ObjectMeta = ObjectMeta(), + spec: Option[Deployment.Spec] = None, + status: Option[Deployment.Status] = None) extends ObjectResource { def withResourceVersion(version: String) = this.copy(metadata = metadata.copy(resourceVersion=version)) - lazy val copySpec = this.spec.getOrElse(new Deployment.Spec(selector=LabelSelector(), template=Pod.Template.Spec())) + lazy val copySpec = this.spec.getOrElse(Deployment.Spec(selector=LabelSelector(), template=Pod.Template.Spec())) def withReplicas(count: Int) = this.copy(spec=Some(copySpec.copy(replicas=Some(count)))) diff --git a/client/src/main/scala/skuber/apps/v1/ReplicaSet.scala b/client/src/main/scala/skuber/apps/v1/ReplicaSet.scala index 8661f94c..a5d62b3f 100644 --- a/client/src/main/scala/skuber/apps/v1/ReplicaSet.scala +++ b/client/src/main/scala/skuber/apps/v1/ReplicaSet.scala @@ -8,14 +8,14 @@ import skuber._ * @author David O'Riordan */ case class ReplicaSet( - val kind: String ="ReplicaSet", - override val apiVersion: String = appsAPIVersion, - val metadata: ObjectMeta = ObjectMeta(), + kind: String ="ReplicaSet", + apiVersion: String = appsAPIVersion, + metadata: ObjectMeta = ObjectMeta(), spec: Option[ReplicaSet.Spec] = None, status: Option[ReplicaSet.Status] = None) extends ObjectResource { - lazy val copySpec = this.spec.getOrElse(new ReplicaSet.Spec(selector=LabelSelector(), template=Pod.Template.Spec())) + lazy val copySpec = this.spec.getOrElse(ReplicaSet.Spec(selector=LabelSelector(), template=Pod.Template.Spec())) def withResourceVersion(version: String) = this.copy(metadata = metadata.copy(resourceVersion=version)) def addLabel(label: Tuple2[String, String]) : ReplicaSet = this.copy(metadata = metadata.copy(labels = metadata.labels + label)) @@ -36,7 +36,7 @@ case class ReplicaSet( def withTemplate(t: Pod.Template.Spec) = { val withTmpl = this.copy(spec = Some(copySpec.copy(template = t))) val withSelector = (t.metadata.labels, spec.map{_.selector}) match { - case (labels, selector) if (!labels.isEmpty && !selector.equals(LabelSelector())) => + case (labels, selector) if labels.nonEmpty && !selector.exists(_.requirements.nonEmpty) => val reqs = labels map { label: (String, String) => LabelSelector.IsEqualRequirement(label._1, label._2) } @@ -46,7 +46,7 @@ case class ReplicaSet( } // copy template labels into RS labels, if not already set (metadata.labels,t.metadata.labels) match { - case (curr,default) if (curr.isEmpty && !default.isEmpty) => + case (curr,default) if curr.isEmpty && default.nonEmpty => withSelector.addLabels(default) case _ => withSelector } diff --git a/client/src/main/scala/skuber/apps/v1/StatefulSet.scala b/client/src/main/scala/skuber/apps/v1/StatefulSet.scala index 4909be07..df5313d5 100644 --- a/client/src/main/scala/skuber/apps/v1/StatefulSet.scala +++ b/client/src/main/scala/skuber/apps/v1/StatefulSet.scala @@ -19,7 +19,7 @@ case class StatefulSet(override val kind: String ="StatefulSet", { def withResourceVersion(version: String) = this.copy(metadata = metadata.copy(resourceVersion=version)) - lazy val copySpec = this.spec.getOrElse(new StatefulSet.Spec(template = Pod.Template.Spec())) + lazy val copySpec = this.spec.getOrElse(StatefulSet.Spec(template = Pod.Template.Spec())) private val rollingUpdateStrategy = StatefulSet.UpdateStrategy(`type`=StatefulSet.UpdateStrategyType.RollingUpdate, None) private def rollingUpdateStrategy(partition: Int)= StatefulSet.UpdateStrategy(`type`=StatefulSet.UpdateStrategyType.RollingUpdate,Some(StatefulSet.RollingUpdateStrategy(partition))) diff --git a/client/src/main/scala/skuber/apps/v1beta1/Deployment.scala b/client/src/main/scala/skuber/apps/v1beta1/Deployment.scala index 610a201e..ce6c346a 100644 --- a/client/src/main/scala/skuber/apps/v1beta1/Deployment.scala +++ b/client/src/main/scala/skuber/apps/v1beta1/Deployment.scala @@ -8,11 +8,11 @@ import skuber.ResourceSpecification.{Names, Scope} import skuber._ case class Deployment( - val kind: String ="Deployment", + kind: String ="Deployment", override val apiVersion: String = appsAPIVersion, - val metadata: ObjectMeta = ObjectMeta(), - val spec: Option[Deployment.Spec] = None, - val status: Option[Deployment.Status] = None) + metadata: ObjectMeta = ObjectMeta(), + spec: Option[Deployment.Spec] = None, + status: Option[Deployment.Status] = None) extends ObjectResource { def withResourceVersion(version: String) = this.copy(metadata = metadata.copy(resourceVersion=version)) diff --git a/client/src/main/scala/skuber/apps/v1beta1/StatefulSet.scala b/client/src/main/scala/skuber/apps/v1beta1/StatefulSet.scala index cd41c90a..fab17d5b 100644 --- a/client/src/main/scala/skuber/apps/v1beta1/StatefulSet.scala +++ b/client/src/main/scala/skuber/apps/v1beta1/StatefulSet.scala @@ -10,11 +10,13 @@ import skuber.json.format._ /** * Created by hollinwilkins on 4/5/17. */ -case class StatefulSet(override val kind: String ="StatefulSet", - override val apiVersion: String = "apps/v1beta1", // correct at k8s 1.7 - metadata: ObjectMeta, - spec: Option[StatefulSet.Spec] = None, - status: Option[StatefulSet.Status] = None) extends ObjectResource +case class StatefulSet( + kind: String ="StatefulSet", + apiVersion: String = "apps/v1beta1", + metadata: ObjectMeta, + spec: Option[StatefulSet.Spec] = None, + status: Option[StatefulSet.Status] = None) + extends ObjectResource { def withResourceVersion(version: String) = this.copy(metadata = metadata.copy(resourceVersion=version)) diff --git a/client/src/main/scala/skuber/autoscaling/HorizontalPodAutoscaler.scala b/client/src/main/scala/skuber/autoscaling/HorizontalPodAutoscaler.scala index ce2609a7..28c2b4b6 100644 --- a/client/src/main/scala/skuber/autoscaling/HorizontalPodAutoscaler.scala +++ b/client/src/main/scala/skuber/autoscaling/HorizontalPodAutoscaler.scala @@ -1,10 +1,9 @@ package skuber.autoscaling -import play.api.libs.functional.syntax.unlift import play.api.libs.json.{Format, Json} import skuber.ResourceSpecification.{Names, Scope} import skuber.{NonCoreResourceSpecification, ObjectMeta, ObjectResource, ReplicationController, ResourceDefinition, Timestamp} -import skuber.json.format.objectMetaFormat +import skuber.json.format._ /** * @author David O'Riordan @@ -15,12 +14,13 @@ import skuber.json.format.objectMetaFormat * */ case class HorizontalPodAutoscaler( - val kind: String ="HorizontalPodAutoscaler", - override val apiVersion: String = "autoscaling/v1", - val metadata: ObjectMeta, - spec: HorizontalPodAutoscaler.Spec, - status: Option[HorizontalPodAutoscaler.Status] = None) - extends ObjectResource { + kind: String ="HorizontalPodAutoscaler", + apiVersion: String = "autoscaling/v1", + metadata: ObjectMeta, + spec: HorizontalPodAutoscaler.Spec, + status: Option[HorizontalPodAutoscaler.Status] = None) + extends ObjectResource +{ def withResourceVersion(version: String) = this.copy(metadata = metadata.copy(resourceVersion=version)) diff --git a/client/src/main/scala/skuber/batch/CronJob.scala b/client/src/main/scala/skuber/batch/CronJob.scala index cb4861e7..5bc57c60 100644 --- a/client/src/main/scala/skuber/batch/CronJob.scala +++ b/client/src/main/scala/skuber/batch/CronJob.scala @@ -1,13 +1,13 @@ package skuber.batch import skuber.ResourceSpecification.{Names, Scope} -import skuber.{ObjectReference, LabelSelector, NonCoreResourceSpecification, ObjectMeta, ObjectResource, Pod, ResourceDefinition, Timestamp} +import skuber.{ObjectReference, NonCoreResourceSpecification, ObjectMeta, ObjectResource, Pod, ResourceDefinition, Timestamp} /** * @author David O'Riordan */ case class CronJob(kind: String ="CronJob", - override val apiVersion: String = "batch/v1beta1", + apiVersion: String = "batch/v1beta1", metadata: ObjectMeta = ObjectMeta(), spec: Option[CronJob.Spec] = None, status: Option[CronJob.Status] = None) extends ObjectResource diff --git a/client/src/main/scala/skuber/batch/Job.scala b/client/src/main/scala/skuber/batch/Job.scala index c6685985..02140318 100644 --- a/client/src/main/scala/skuber/batch/Job.scala +++ b/client/src/main/scala/skuber/batch/Job.scala @@ -6,13 +6,16 @@ import skuber.{LabelSelector, NonCoreResourceSpecification, ObjectMeta, ObjectRe /** * @author Cory Klein */ -case class Job(val kind: String = "Job", - override val apiVersion: String = batchAPIVersion, - val metadata: ObjectMeta = ObjectMeta(), - spec: Option[Job.Spec] = None, - status: Option[Job.Status] = None) extends ObjectResource { +case class Job( + kind: String = "Job", + override val apiVersion: String = batchAPIVersion, + metadata: ObjectMeta = ObjectMeta(), + spec: Option[Job.Spec] = None, + status: Option[Job.Status] = None) + extends ObjectResource +{ - lazy val copySpec: Job.Spec = this.spec.getOrElse(new Job.Spec()) + lazy val copySpec: Job.Spec = this.spec.getOrElse(Job.Spec()) def withTemplate(template: Pod.Template.Spec) = this.copy(spec = Some(copySpec.copy(template = Some(template)))) def withParallelism(parallelism: Int) = this.copy(spec = Some(copySpec.copy(parallelism = Some(parallelism)))) diff --git a/client/src/main/scala/skuber/batch/JobTemplate.scala b/client/src/main/scala/skuber/batch/JobTemplate.scala index d33656a1..daa8810c 100644 --- a/client/src/main/scala/skuber/batch/JobTemplate.scala +++ b/client/src/main/scala/skuber/batch/JobTemplate.scala @@ -1,6 +1,6 @@ package skuber.batch -import skuber.{ObjectMeta, ObjectResource} +import skuber.ObjectMeta /** * @author David O'Riordan */ diff --git a/client/src/main/scala/skuber/ext/Deployment.scala b/client/src/main/scala/skuber/ext/Deployment.scala index b68a0388..36a2f137 100644 --- a/client/src/main/scala/skuber/ext/Deployment.scala +++ b/client/src/main/scala/skuber/ext/Deployment.scala @@ -9,12 +9,13 @@ import skuber.ResourceSpecification.{Names, Scope} import skuber.{Container, IntOrString, LabelSelector, NonCoreResourceSpecification, ObjectMeta, ObjectResource, Pod, ListResource, ResourceDefinition} case class Deployment( - val kind: String ="Deployment", - override val apiVersion: String = extensionsAPIVersion, - val metadata: ObjectMeta = ObjectMeta(), - val spec: Option[Deployment.Spec] = None, - val status: Option[Deployment.Status] = None) - extends ObjectResource { + kind: String ="Deployment", + apiVersion: String = extensionsAPIVersion, + metadata: ObjectMeta = ObjectMeta(), + spec: Option[Deployment.Spec] = None, + status: Option[Deployment.Status] = None) + extends ObjectResource +{ def withResourceVersion(version: String): Deployment = this.copy(metadata = metadata.copy(resourceVersion = version)) diff --git a/client/src/main/scala/skuber/ext/ReplicaSet.scala b/client/src/main/scala/skuber/ext/ReplicaSet.scala index d03f0dc5..00d8e1ba 100644 --- a/client/src/main/scala/skuber/ext/ReplicaSet.scala +++ b/client/src/main/scala/skuber/ext/ReplicaSet.scala @@ -7,12 +7,13 @@ import skuber._ * @author David O'Riordan */ case class ReplicaSet( - val kind: String ="ReplicaSet", - override val apiVersion: String = extensionsAPIVersion, - val metadata: ObjectMeta = ObjectMeta(), - spec: Option[ReplicaSet.Spec] = None, - status: Option[ReplicaSet.Status] = None) - extends ObjectResource { + kind: String ="ReplicaSet", + apiVersion: String = extensionsAPIVersion, + metadata: ObjectMeta = ObjectMeta(), + spec: Option[ReplicaSet.Spec] = None, + status: Option[ReplicaSet.Status] = None) + extends ObjectResource +{ lazy val copySpec = this.spec.getOrElse(new ReplicaSet.Spec) @@ -35,7 +36,7 @@ case class ReplicaSet( def withTemplate(t: Pod.Template.Spec) = { val withTmpl = this.copy(spec = Some(copySpec.copy(template = Some(t)))) val withSelector = (t.metadata.labels, spec.flatMap{_.selector}) match { - case (labels, selector) if (!labels.isEmpty && !selector.isDefined) => + case (labels, selector) if !labels.isEmpty && !selector.exists(_.requirements.nonEmpty) => val reqs = labels map { label: (String, String) => LabelSelector.IsEqualRequirement(label._1, label._2) } diff --git a/client/src/main/scala/skuber/ext/package.scala b/client/src/main/scala/skuber/ext/package.scala index 5359d4f6..c443698e 100644 --- a/client/src/main/scala/skuber/ext/package.scala +++ b/client/src/main/scala/skuber/ext/package.scala @@ -12,15 +12,9 @@ package skuber * @author David O'Riordan */ -import akka.http.scaladsl.marshalling.Marshal - import scala.language.implicitConversions import scala.concurrent.Future -import skuber.json.ext.format._ import skuber.api.client._ -import akka.http.scaladsl.model._ -import skuber.json.PlayJsonSupportForAkkaHttp._ -import skuber.networking.Ingress package object ext { val extensionsAPIVersion = "extensions/v1beta1" diff --git a/client/src/main/scala/skuber/json/PlayJsonSupportForAkkaHttp.scala b/client/src/main/scala/skuber/json/PlayJsonSupportForAkkaHttp.scala index 2e9d50ae..55154eeb 100644 --- a/client/src/main/scala/skuber/json/PlayJsonSupportForAkkaHttp.scala +++ b/client/src/main/scala/skuber/json/PlayJsonSupportForAkkaHttp.scala @@ -30,7 +30,6 @@ import akka.http.scaladsl.server.{ RejectionError, ValidationRejection } import akka.http.scaladsl.unmarshalling.{ FromEntityUnmarshaller, Unmarshaller } import akka.util.ByteString import play.api.libs.json.{ JsError, JsValue, Json, Reads, Writes } -import scala.collection.immutable.Seq /** * Automatic to and from JSON marshalling/unmarshalling using an in-scope *play-json* protocol. diff --git a/client/src/main/scala/skuber/json/annotation/format/package.scala b/client/src/main/scala/skuber/json/annotation/format/package.scala index e67b82ff..e9029ed6 100644 --- a/client/src/main/scala/skuber/json/annotation/format/package.scala +++ b/client/src/main/scala/skuber/json/annotation/format/package.scala @@ -20,15 +20,12 @@ package object format { (JsPath \ "values").formatMaybeEmptyList[String] )(MatchExpression.apply _, unlift(MatchExpression.unapply)) - implicit val nodeSelectorTermFormat: Format[NodeSelectorTerm] = ( + implicit val nodeSelectorTermFormat: Format[NodeSelectorTerm] = (JsPath \ "matchExpressions").format[MatchExpressions].inmap(matchExpressions => NodeSelectorTerm(matchExpressions), (nst: NodeSelectorTerm) => nst.matchExpressions) - ) - implicit val requiredDuringSchedulingIgnoredDuringExecutionFormat: Format[RequiredDuringSchedulingIgnoredDuringExecution] = ( + implicit val requiredDuringSchedulingIgnoredDuringExecutionFormat: Format[RequiredDuringSchedulingIgnoredDuringExecution] = (JsPath \ "nodeSelectorTerms").format[NodeSelectorTerms].inmap(nodeSelectorTerms => RequiredDuringSchedulingIgnoredDuringExecution(nodeSelectorTerms), (rdside: RequiredDuringSchedulingIgnoredDuringExecution) => rdside.nodeSelectorTerms) - ) - implicit val preferredDuringSchedulingIgnoredDuringExecutionFormat: Format[PreferredDuringSchedulingIgnoredDuringExecution] = ( + implicit val preferredDuringSchedulingIgnoredDuringExecutionFormat: Format[PreferredDuringSchedulingIgnoredDuringExecution] = (JsPath \ "nodeSelectorTerms").format[NodeSelectorTerms].inmap(nodeSelectorTerms => PreferredDuringSchedulingIgnoredDuringExecution(nodeSelectorTerms), (pdside: PreferredDuringSchedulingIgnoredDuringExecution) => pdside.nodeSelectorTerms) - ) } diff --git a/client/src/main/scala/skuber/networking/Ingress.scala b/client/src/main/scala/skuber/networking/Ingress.scala index 29a5e0d1..eee923a0 100644 --- a/client/src/main/scala/skuber/networking/Ingress.scala +++ b/client/src/main/scala/skuber/networking/Ingress.scala @@ -10,11 +10,12 @@ import scala.util.Try case class Ingress( kind: String ="Ingress", - override val apiVersion: String = "networking.k8s.io/v1beta1", + apiVersion: String = "networking.k8s.io/v1beta1", metadata: ObjectMeta = ObjectMeta(), spec: Option[Ingress.Spec] = None, status: Option[Ingress.Status] = None) - extends ObjectResource { + extends ObjectResource +{ import skuber.networking.Ingress.Backend diff --git a/client/src/main/scala/skuber/networking/NetworkPolicy.scala b/client/src/main/scala/skuber/networking/NetworkPolicy.scala index 102c62bc..772e951e 100644 --- a/client/src/main/scala/skuber/networking/NetworkPolicy.scala +++ b/client/src/main/scala/skuber/networking/NetworkPolicy.scala @@ -1,7 +1,7 @@ package skuber.networking import skuber.ResourceSpecification.{Names, Scope} -import skuber.{LabelSelector, NameablePort, NonCoreResourceSpecification, ObjectMeta, ObjectResource, Pod, Protocol, ResourceDefinition} +import skuber.{LabelSelector, NameablePort, NonCoreResourceSpecification, ObjectMeta, ObjectResource, Protocol, ResourceDefinition} import play.api.libs.functional.syntax._ import play.api.libs.json.{Format, JsPath} import skuber.json.format.{objFormat,enumFormatMethods, intOrStringFormat, jsPath2LabelSelFormat, maybeEmptyFormatMethods} @@ -11,10 +11,11 @@ import skuber.json.format.{objFormat,enumFormatMethods, intOrStringFormat, jsPat * This supports NetworkPolicy on Kubernetes V1.7+ (earlier beta version of this resource type not supported) */ case class NetworkPolicy( - val kind: String ="NetworkPolicy", - override val apiVersion: String = "networking.k8s.io/v1", - val metadata: ObjectMeta, - spec: Option[NetworkPolicy.Spec]=None) extends ObjectResource + kind: String ="NetworkPolicy", + apiVersion: String = "networking.k8s.io/v1", + metadata: ObjectMeta, + spec: Option[NetworkPolicy.Spec]=None) + extends ObjectResource { private def specSelectingAllPods=Some(NetworkPolicy.Spec(podSelector=LabelSelector())) private def fallbackToSelectingAllPods=this.copy(spec=this.spec.orElse(specSelectingAllPods)) diff --git a/client/src/main/scala/skuber/policy/v1beta1/PodDisruptionBudget.scala b/client/src/main/scala/skuber/policy/v1beta1/PodDisruptionBudget.scala index a2829edb..c777e8e9 100644 --- a/client/src/main/scala/skuber/policy/v1beta1/PodDisruptionBudget.scala +++ b/client/src/main/scala/skuber/policy/v1beta1/PodDisruptionBudget.scala @@ -3,11 +3,13 @@ package skuber.policy.v1beta1 import skuber.ResourceSpecification.{Names, Scope} import skuber.{IntOrString, LabelSelector, NonCoreResourceSpecification, ObjectMeta, ObjectResource, ResourceDefinition, Scale, Timestamp} -case class PodDisruptionBudget(override val kind: String = "PodDisruptionBudget", - override val apiVersion: String = policyAPIVersion, - metadata: ObjectMeta, - spec: Option[PodDisruptionBudget.Spec] = None, - status: Option[PodDisruptionBudget.Status] = None) extends ObjectResource { +case class PodDisruptionBudget( + kind: String = "PodDisruptionBudget", + apiVersion: String = policyAPIVersion, + metadata: ObjectMeta, + spec: Option[PodDisruptionBudget.Spec] = None, + status: Option[PodDisruptionBudget.Status] = None) extends ObjectResource +{ private lazy val copySpec: PodDisruptionBudget.Spec = this.spec.getOrElse(PodDisruptionBudget.Spec(selector=Some(LabelSelector()))) diff --git a/client/src/main/scala/skuber/rbac/ClusterRole.scala b/client/src/main/scala/skuber/rbac/ClusterRole.scala index 95dc32b0..fc904894 100644 --- a/client/src/main/scala/skuber/rbac/ClusterRole.scala +++ b/client/src/main/scala/skuber/rbac/ClusterRole.scala @@ -7,10 +7,10 @@ import skuber.{NonCoreResourceSpecification, ObjectMeta, ObjectResource, Resourc * Created by jordan on 1/12/17. */ case class ClusterRole( - kind: String = "ClusterRole", - override val apiVersion: String = rbacAPIVersion, - metadata: ObjectMeta = ObjectMeta(), - rules: List[PolicyRule] + kind: String = "ClusterRole", + apiVersion: String = rbacAPIVersion, + metadata: ObjectMeta = ObjectMeta(), + rules: List[PolicyRule] ) extends ObjectResource object ClusterRole { diff --git a/client/src/main/scala/skuber/rbac/ClusterRoleBinding.scala b/client/src/main/scala/skuber/rbac/ClusterRoleBinding.scala index d13c9875..447d028f 100644 --- a/client/src/main/scala/skuber/rbac/ClusterRoleBinding.scala +++ b/client/src/main/scala/skuber/rbac/ClusterRoleBinding.scala @@ -7,11 +7,11 @@ import skuber.{NonCoreResourceSpecification, ObjectMeta, ObjectResource, Resourc * Created by jordan on 1/12/17. */ case class ClusterRoleBinding( - kind: String = "ClusterRoleBinding", - apiVersion: String = rbacAPIVersion, - metadata: ObjectMeta, - roleRef: Option[RoleRef], - subjects: List[Subject]) extends ObjectResource + kind: String = "ClusterRoleBinding", + apiVersion: String = rbacAPIVersion, + metadata: ObjectMeta, + roleRef: Option[RoleRef], + subjects: List[Subject]) extends ObjectResource object ClusterRoleBinding { diff --git a/client/src/main/scala/skuber/rbac/PolicyRule.scala b/client/src/main/scala/skuber/rbac/PolicyRule.scala index 0229359f..8d0d880c 100644 --- a/client/src/main/scala/skuber/rbac/PolicyRule.scala +++ b/client/src/main/scala/skuber/rbac/PolicyRule.scala @@ -4,12 +4,9 @@ package skuber.rbac * Created by jordan on 1/12/17. */ case class PolicyRule( - apiGroups: List[String], - attributeRestrictions: Option[String], - nonResourceURLs: List[String], - resourceNames: List[String], - resources: List[String], - verbs: List[String] -) { - -} + apiGroups: List[String], + attributeRestrictions: Option[String], + nonResourceURLs: List[String], + resourceNames: List[String], + resources: List[String], + verbs: List[String]) diff --git a/client/src/main/scala/skuber/rbac/RoleBinding.scala b/client/src/main/scala/skuber/rbac/RoleBinding.scala index ac359307..f5050dbd 100644 --- a/client/src/main/scala/skuber/rbac/RoleBinding.scala +++ b/client/src/main/scala/skuber/rbac/RoleBinding.scala @@ -7,11 +7,11 @@ import skuber.{NonCoreResourceSpecification, ObjectMeta, ObjectResource, Resourc * Created by jordan on 1/12/17. */ case class RoleBinding( - kind: String = "RoleBinding", - apiVersion: String = rbacAPIVersion, - metadata: ObjectMeta, - roleRef: RoleRef, - subjects: List[Subject] + kind: String = "RoleBinding", + apiVersion: String = rbacAPIVersion, + metadata: ObjectMeta, + roleRef: RoleRef, + subjects: List[Subject] ) extends ObjectResource object RoleBinding { diff --git a/client/src/main/scala/skuber/rbac/RoleRef.scala b/client/src/main/scala/skuber/rbac/RoleRef.scala index 224aabea..f439618f 100644 --- a/client/src/main/scala/skuber/rbac/RoleRef.scala +++ b/client/src/main/scala/skuber/rbac/RoleRef.scala @@ -3,10 +3,4 @@ package skuber.rbac /** * Created by jordan on 1/13/17. */ -case class RoleRef( - apiGroup: String, - kind: String, - name: String -) { - -} +case class RoleRef(apiGroup: String, kind: String, name: String) diff --git a/client/src/main/scala/skuber/rbac/Subject.scala b/client/src/main/scala/skuber/rbac/Subject.scala index de82b20b..12fee381 100644 --- a/client/src/main/scala/skuber/rbac/Subject.scala +++ b/client/src/main/scala/skuber/rbac/Subject.scala @@ -3,11 +3,4 @@ package skuber.rbac /** * Created by jordan on 1/13/17. */ -case class Subject( - apiVersion: Option[String], - kind: String, - name: String, - namespace: Option[String] -) { - -} +case class Subject(apiVersion: Option[String], kind: String, name: String, namespace: Option[String]) diff --git a/client/src/main/scala/skuber/settings/PodPreset.scala b/client/src/main/scala/skuber/settings/PodPreset.scala index ec72f63e..0e1f398a 100644 --- a/client/src/main/scala/skuber/settings/PodPreset.scala +++ b/client/src/main/scala/skuber/settings/PodPreset.scala @@ -11,9 +11,9 @@ import skuber.{EnvFromSource, EnvVar, LabelSelector, NonCoreResourceSpecificatio */ case class PodPreset( - val kind: String ="PodPreset", - override val apiVersion: String = "settings.k8s.io/v1alpha1", - val metadata: ObjectMeta, + kind: String ="PodPreset", + apiVersion: String = "settings.k8s.io/v1alpha1", + metadata: ObjectMeta, spec: Option[PodPreset.Spec]=None) extends ObjectResource object PodPreset { diff --git a/client/src/test/scala/skuber/api/ConfigurationSpec.scala b/client/src/test/scala/skuber/api/ConfigurationSpec.scala index e71dc8c0..d65ad12c 100644 --- a/client/src/test/scala/skuber/api/ConfigurationSpec.scala +++ b/client/src/test/scala/skuber/api/ConfigurationSpec.scala @@ -1,15 +1,12 @@ package skuber.api -import skuber._ -import org.specs2.mutable.Specification import java.nio.file.Paths -import java.time.format.DateTimeFormatter -import java.time.{Instant, ZoneId} - -import akka.actor.ActorSystem -import com.typesafe.config.ConfigFactory +import java.time.Instant import scala.util.Try +import org.specs2.mutable.Specification +import akka.actor.ActorSystem +import skuber._ import skuber.api.client._ /** diff --git a/examples/src/main/scala/skuber/examples/deployment/DeploymentExamples.scala b/examples/src/main/scala/skuber/examples/deployment/DeploymentExamples.scala index 044ad9ba..70a031ea 100644 --- a/examples/src/main/scala/skuber/examples/deployment/DeploymentExamples.scala +++ b/examples/src/main/scala/skuber/examples/deployment/DeploymentExamples.scala @@ -67,7 +67,7 @@ object DeploymentExamples extends App { println("Deleting deployment, including its owned resources") val deleteOptions=DeleteOptions(propagationPolicy = Some(DeletePropagation.Foreground)) val deleteFut=k8s.deleteWithOptions[Deployment](nginxDeploymentName, deleteOptions) - Await.ready(deleteFut, 30 seconds) + Await.ready(deleteFut, 30.seconds) println("DSuccessfully completed, exiting") system.terminate().foreach { f => System.exit(0) diff --git a/project/build.properties b/project/build.properties index 67d27a1d..563a014d 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.5.3 +sbt.version=1.7.2 diff --git a/project/plugins.sbt b/project/plugins.sbt index a36b55dd..acebe5cd 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,4 +1,4 @@ -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.0.0") -addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.1") -addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.7") +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0") +addSbtPlugin("com.github.sbt" % "sbt-git" % "2.0.0") +addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.13") addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2")