From e1ca18ceb793926cd3e2d040e5732726301964b8 Mon Sep 17 00:00:00 2001 From: David Cawley Date: Fri, 28 Feb 2025 10:35:49 +0000 Subject: [PATCH 1/2] add topologySpreadConstraints to Pod spec --- build.sbt | 2 +- client/src/main/scala/skuber/Pod.scala | 7 ++++++ .../src/main/scala/skuber/json/package.scala | 22 ++++++++++++++----- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/build.sbt b/build.sbt index 24d50417..0b709a32 100644 --- a/build.sbt +++ b/build.sbt @@ -31,7 +31,7 @@ scalacOptions += "-target:jvm-1.8" scalacOptions in Test ++= Seq("-Yrangepos") -ThisBuild / version := "2.6.7" +ThisBuild / version := "2.7.0" sonatypeProfileName := "io.skuber" diff --git a/client/src/main/scala/skuber/Pod.scala b/client/src/main/scala/skuber/Pod.scala index 76a42eba..167946bb 100644 --- a/client/src/main/scala/skuber/Pod.scala +++ b/client/src/main/scala/skuber/Pod.scala @@ -39,6 +39,7 @@ object Pod { imagePullSecrets: List[LocalObjectReference] = List(), affinity: Option[Affinity] = None, tolerations: List[Toleration] = List(), + topologySpreadConstraints: List[TopologySpreadConstraints] = List(), securityContext: Option[PodSecurityContext] = None, hostname: Option[String] = None, hostAliases: List[HostAlias] = Nil, @@ -153,6 +154,12 @@ object Pod { case class DNSConfigOption(name: String, value: String) case class DNSConfig(nameservers: List[String] = Nil, options: List[DNSConfigOption] = Nil, searches: List[String] = Nil) + case class TopologySpreadConstraints( + maxSkew: Int, + topologyKey: String, + whenUnsatisfiable: String, + labelSelector: Option[LabelSelector] = None) + case class Status( phase: Option[Phase.Phase] = None, conditions: List[Condition] = Nil, diff --git a/client/src/main/scala/skuber/json/package.scala b/client/src/main/scala/skuber/json/package.scala index 4e2baf14..6c6b125e 100644 --- a/client/src/main/scala/skuber/json/package.scala +++ b/client/src/main/scala/skuber/json/package.scala @@ -3,10 +3,10 @@ package skuber.json import scala.language.implicitConversions import java.time._ import java.time.format._ - import org.apache.commons.codec.binary.Base64 import play.api.libs.functional.syntax._ import play.api.libs.json._ +import skuber.Pod.TopologySpreadConstraints import skuber.Volume.{ConfigMapVolumeSource, KeyToPath} import skuber._ import skuber.annotation.MatchExpression @@ -251,6 +251,16 @@ package object format { implicit val secCtxtFormat: Format[SecurityContext] = Json.format[SecurityContext] + implicit val labelSelectorForrmat: Format[LabelSelector] = ( + (JsPath \ "matchLabels").formatNullable[Map[String, String]] and + (JsPath \ "matchExpressions").formatNullable[List[SelMatchExpression]] + )(OnTheWireSelector.apply _, unlift(OnTheWireSelector.unapply)).inmap[LabelSelector]( + otwSelectorToLabelSelector, + labelSelToOtwSelector + ) + + implicit val topologySpreadConstraintsFormat: Format[TopologySpreadConstraints] = Json.format[TopologySpreadConstraints] + implicit val podSecCtxtFormat: Format[PodSecurityContext] = ( (JsPath \ "fsGroup").formatNullable[Int] and (JsPath \ "runAsGroup").formatNullable[Int] and @@ -807,7 +817,7 @@ package object format { // which has finally necessitated a hack to get around Play Json limitations supporting case classes with > 22 members // (see e.g. https://stackoverflow.com/questions/28167971/scala-case-having-22-fields-but-having-issue-with-play-json-in-scala-2-11-5) - val podSpecPartOneFormat: OFormat[(List[Container], List[Container], List[Volume], skuber.RestartPolicy.Value, Option[Int], Option[Int], skuber.DNSPolicy.Value, Map[String, String], String, String, Boolean, List[LocalObjectReference], Option[Pod.Affinity], List[Pod.Toleration], Option[PodSecurityContext])] = ( + val podSpecPartOneFormat: OFormat[(List[Container], List[Container], List[Volume], skuber.RestartPolicy.Value, Option[Int], Option[Int], skuber.DNSPolicy.Value, Map[String, String], String, String, Boolean, List[LocalObjectReference], Option[Pod.Affinity], List[Pod.Toleration], List[TopologySpreadConstraints], Option[PodSecurityContext])] = ( (JsPath \ "containers").format[List[Container]] and (JsPath \ "initContainers").formatMaybeEmptyList[Container] and (JsPath \ "volumes").formatMaybeEmptyList[Volume] and @@ -822,6 +832,7 @@ package object format { (JsPath \ "imagePullSecrets").formatMaybeEmptyList[LocalObjectReference] and (JsPath \ "affinity").formatNullable[Pod.Affinity] and (JsPath \ "tolerations").formatMaybeEmptyList[Pod.Toleration] and + (JsPath \ "topologySpreadConstraints").formatMaybeEmptyList[TopologySpreadConstraints] and (JsPath \ "securityContext").formatNullable[PodSecurityContext] ).tupled @@ -840,13 +851,13 @@ package object format { ).tupled def fromTuples( - partOne: (scala.List[Container], scala.List[Container], scala.List[Volume], skuber.RestartPolicy.Value, Option[Int], Option[Int], skuber.DNSPolicy.Value, Map[String, String], String, String, Boolean, scala.List[skuber.LocalObjectReference], Option[Pod.Affinity], scala.List[Pod.Toleration], Option[PodSecurityContext]), + partOne: (scala.List[Container], scala.List[Container], scala.List[Volume], skuber.RestartPolicy.Value, Option[Int], Option[Int], skuber.DNSPolicy.Value, Map[String, String], String, String, Boolean, scala.List[skuber.LocalObjectReference], Option[Pod.Affinity], scala.List[Pod.Toleration], List[TopologySpreadConstraints], Option[PodSecurityContext]), partTwo: (Option[String], scala.List[Pod.HostAlias], Option[Boolean], Option[Boolean], Option[Boolean], Option[Int], Option[String], Option[String], Option[String], Option[Pod.DNSConfig], Option[Boolean]) ): Pod.Spec = { - val (conts, initConts, vols, rpol, tgps, adls, dnspol, nodesel, svcac, node, hnet, ips, aff, tol, psc) = partOne + val (conts, initConts, vols, rpol, tgps, adls, dnspol, nodesel, svcac, node, hnet, ips, aff, tol, tsc, psc) = partOne val (host, aliases, pid, ipc, asat, prio, prioc, sched, subd, dnsc, spn) = partTwo - Pod.Spec(conts, initConts, vols, rpol, tgps, adls, dnspol, nodesel, svcac, node, hnet, ips, aff, tol, psc, host, aliases, pid, ipc, asat, prio, prioc, sched, subd, dnsc, spn) + Pod.Spec(conts, initConts, vols, rpol, tgps, adls, dnspol, nodesel, svcac, node, hnet, ips, aff, tol, tsc, psc, host, aliases, pid, ipc, asat, prio, prioc, sched, subd, dnsc, spn) } implicit val podSpecFmt: Format[Pod.Spec] = ( @@ -868,6 +879,7 @@ package object format { s.imagePullSecrets, s.affinity, s.tolerations, + s.topologySpreadConstraints, s.securityContext ), ( s.hostname, From 0b9a2d17cfa037ccc45a5f170885764108e2aeb7 Mon Sep 17 00:00:00 2001 From: David Cawley Date: Fri, 28 Feb 2025 11:09:53 +0000 Subject: [PATCH 2/2] remove release version change --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 0b709a32..24d50417 100644 --- a/build.sbt +++ b/build.sbt @@ -31,7 +31,7 @@ scalacOptions += "-target:jvm-1.8" scalacOptions in Test ++= Seq("-Yrangepos") -ThisBuild / version := "2.7.0" +ThisBuild / version := "2.6.7" sonatypeProfileName := "io.skuber"