Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: hagay3/skuber
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v3.0.1
Choose a base ref
...
head repository: hagay3/skuber
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v3.0.2
Choose a head ref
  • 14 commits
  • 7 files changed
  • 5 contributors

Commits on Sep 13, 2022

  1. Verified

    This commit was signed with the committer’s verified signature.
    scala-steward Scala Steward
    Copy the full SHA
    b89d6c5 View commit details
  2. Merge pull request #231 from scala-steward/update/snakeyaml-1.32

    Update snakeyaml to 1.32
    hagay3 authored Sep 13, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    2fe96fe View commit details
  3. akka open source comment

    hagay3 committed Sep 13, 2022
    Copy the full SHA
    245444b View commit details
  4. akka open source comment

    hagay3 committed Sep 13, 2022
    Copy the full SHA
    98405b0 View commit details

Commits on Sep 14, 2022

  1. Create Ingress.scala

    coralbg authored Sep 14, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    9c7852d View commit details
  2. Create package.scala

    coralbg authored Sep 14, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    2f2b9d5 View commit details
  3. Create IngressSpec.scala

    coralbg authored Sep 14, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    9b3ae4f View commit details
  4. Update Ingress.scala

    coralbg authored Sep 14, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    0ac581e View commit details
  5. Update Ingress.scala

    coralbg authored Sep 14, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    03058ad View commit details
  6. Merge pull request #233 from coralbg/master

    Add support for Ingress api networking.k8s.io/v1
    hagay3 authored Sep 14, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    0697542 View commit details

Commits on Sep 15, 2022

  1. Copy the full SHA
    69c9ab6 View commit details

Commits on Sep 16, 2022

  1. Merge pull request #234 from gadomsky/fix.ingress.port

    Fix ingress port so it's complient with 'networking.k8s.io/v1' specification
    hagay3 authored Sep 16, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    dd2700d View commit details
  2. v3.0.2

    hagay3 committed Sep 16, 2022
    Copy the full SHA
    cf2caf7 View commit details
  3. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    ea25068 View commit details
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -71,7 +71,7 @@ You can use the latest release by adding to your build:
- Scala 3.2, 2.13, 2.12 support

```sbt
libraryDependencies += "io.github.hagay3" %% "skuber" % "3.0.1"
libraryDependencies += "io.github.hagay3" %% "skuber" % "3.0.2"
```

## Building
8 changes: 6 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -13,7 +13,11 @@ ThisBuild / scalaVersion := currentScalaVersion

val supportedScalaVersion = Seq(scala12Version, scala13Version, scala3Version)


/**
* 2.6.19 is the last akka open source version
* To comply with other companies' legal issues, akka version wont be bumped.
* https://www.lightbend.com/blog/why-we-are-changing-the-license-for-akka
*/
val akkaVersion = "2.6.19"

val scalaCheck = "org.scalacheck" %% "scalacheck" % "1.15.4"
@@ -24,7 +28,7 @@ val scalaTest = "org.scalatest" %% "scalatest" % "3.2.13"
val akkaStreamTestKit = ("com.typesafe.akka" %% "akka-stream-testkit" % akkaVersion).cross(CrossVersion.for3Use2_13)


val snakeYaml = "org.yaml" % "snakeyaml" % "1.30"
val snakeYaml = "org.yaml" % "snakeyaml" % "1.32"

val commonsIO = "commons-io" % "commons-io" % "2.11.0"
val commonsCodec = "commons-codec" % "commons-codec" % "1.15"
276 changes: 276 additions & 0 deletions client/src/main/scala/skuber/networking/v1/Ingress.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
package skuber.networking.v1

import play.api.libs.json.{Format, JsPath, Json}
import skuber.ResourceSpecification.{Names, Scope}
import skuber.networking.v1.Ingress.PathType.{ImplementationSpecific, PathType}
import skuber.{NameablePort, NonCoreResourceSpecification, ObjectMeta, ObjectResource, ResourceDefinition}

import scala.util.Try

case class Ingress(
kind: String = "Ingress",
override val apiVersion: String = ingressAPIVersion,
metadata: ObjectMeta = ObjectMeta(),
spec: Option[Ingress.Spec] = None,
status: Option[Ingress.Status] = None)
extends ObjectResource {

import Ingress.Backend

lazy val copySpec: Ingress.Spec = this.spec.getOrElse(new Ingress.Spec)

/**
* Fluent API method for building out ingress rules e.g.
* {{{
* val ingress = Ingress("microservices").
* addHttpRule("foo.bar.com",
* ImplementationSpecific,
* Map("/order" -> "orderService:80",
* "inventory" -> "inventoryService:80")).
* addHttpRule("foo1.bar.com",
* Map("/ship" -> "orderService:80",
* "inventory" -> "inventoryService:80")).
* }}}
*/
def addHttpRule(host: String, pathType: PathType, pathsMap: Map[String, String]): Ingress =
addHttpRule(Some(host), pathType: PathType, pathsMap)

/**
* Fluent API method for building out ingress rules without host e.g.
* {{{
* val ingress = Ingress("microservices").
* addHttpRule(ImplementationSpecific,
* Map("/order" -> "orderService:80",
* "inventory" -> "inventoryService:80")).
* addHttpRule(ImplementationSpecific,
* Map("/ship" -> "orderService:80",
* "inventory" -> "inventoryService:80")).
* }}}
*/
def addHttpRule(pathType: PathType, pathsMap: Map[String, String]): Ingress =
addHttpRule(Option.empty, pathType: PathType, pathsMap)

/**
* Fluent API method for building out ingress rules e.g.
* {{{
* val ingress =
* Ingress("microservices")
* .addHttpRule("foo.bar.com",
* ImplementationSpecific,
* "/order" -> "orderService:80",
* "inventory" -> "inventoryService:80")
* .addHttpRule("foo1.bar.com",
* ImplementationSpecific,
* "/ship" -> "orderService:80",
* "inventory" -> "inventoryService:80").
* }}}
*/
def addHttpRule(host: String, pathType: PathType, pathsMap: (String, String)*): Ingress =
addHttpRule(Some(host), pathType: PathType, pathsMap.toMap)

/**
* Fluent API method for building out ingress rules without host e.g.
* {{{
* val ingress =
* Ingress("microservices")
* .addHttpRule(ImplementationSpecific,
* "/order" -> "orderService:80",
* "inventory" -> "inventoryService:80")
* .addHttpRule(ImplementationSpecific,
* "/ship" -> "orderService:80",
* "inventory" -> "inventoryService:80").
* }}}
*/
def addHttpRule(pathType: PathType, pathsMap: (String, String)*): Ingress =
addHttpRule(Option.empty, pathType, pathsMap.toMap)

private val backendSpec = "(\\S+):(\\S+)".r

/**
* Fluent API method for building out ingress rules e.g.
* {{{
* val ingress =
* Ingress("microservices")
* .addHttpRule(Some("foo.bar.com"),
* Exact,
* Map("/order" -> "orderService:80",
* "inventory" -> "inventoryService:80"))
* .addHttpRule(None,
* ImplementationSpecific,
* Map("/ship" -> "orderService:80",
* "inventory" -> "inventoryService:80")).
* }}}
*/
def addHttpRule(host: Option[String], pathType: PathType, pathsMap: Map[String, String]): Ingress = {
val paths: List[Ingress.Path] = pathsMap.map {
case (path: String, backendService: String) =>
backendService match {
case backendSpec(serviceName, servicePort) =>
Ingress.Path(
path,
Ingress.Backend(
Option(Ingress.ServiceType(serviceName, toIngressPort(toNameablePort(servicePort))))
),
pathType
)
case _ =>
throw new Exception(
s"invalid backend format: expected 'serviceName:servicePort' (got '$backendService', for host: $host)"
)
}

}.toList
val httpRule = Ingress.HttpRule(paths)
val rule = Ingress.Rule(host, httpRule)
val withRuleSpec = copySpec.copy(rules = copySpec.rules :+ rule)

this.copy(spec = Some(withRuleSpec))
}

/**
* set the default backend i.e. if no ingress rule matches the incoming traffic then it gets routed to the specified service
*
* @param serviceNameAndPort - service name and port as 'serviceName:servicePort'
* @return copy of this Ingress with default backend set
*/
def withDefaultBackendService(serviceNameAndPort: String): Ingress = {
serviceNameAndPort match {
case backendSpec(serviceName, servicePort) =>
withDefaultBackendService(serviceName, toNameablePort(servicePort))
case _ =>
throw new Exception(s"invalid default backend format: expected 'serviceName:servicePort' (got '$serviceNameAndPort')")
}
}

/**
* set the default backend i.e. if no ingress rule matches the incoming traffic then it gets routed to the specified service
*
* @param serviceName - service name
* @param servicePort - service port
* @return copy of this Ingress with default backend set
*/
def withDefaultBackendService(serviceName: String, servicePort: NameablePort): Ingress = {
val be = Backend(Option(Ingress.ServiceType(serviceName, toIngressPort(servicePort))))
this.copy(spec = Some(copySpec.copy(backend = Some(be))))
}

def addAnnotations(newAnnos: Map[String, String]): Ingress =
this.copy(metadata = this.metadata.copy(annotations = this.metadata.annotations ++ newAnnos))

private def toIngressPort(port: NameablePort): Ingress.Port = port match {
case Left(intValue) => Ingress.Port(number = Some(intValue))
case Right(strValue) => Ingress.Port(name = Some(strValue))
}

private def toNameablePort(port: String): NameablePort =
Try(port.toInt).toEither.left.map(_ => port).swap
}

object Ingress {
val specification: NonCoreResourceSpecification = NonCoreResourceSpecification(
apiGroup = "networking.k8s.io",
version = "v1",
scope = Scope.Namespaced,
names = Names(
plural = "ingresses",
singular = "ingress",
kind = "Ingress",
shortNames = List("ing")
)
)

implicit val ingDef : ResourceDefinition[Ingress] = new ResourceDefinition[Ingress] {
def spec: NonCoreResourceSpecification = specification
}
implicit val ingListDef: ResourceDefinition[IngressList] = new ResourceDefinition[IngressList] {
def spec: NonCoreResourceSpecification = specification
}

def apply(name: String): Ingress = Ingress(metadata = ObjectMeta(name = name))

case class Port(name: Option[String] = None, number: Option[Int] = None)
case class ServiceType(name: String, port: Port)

// Backend contains either service or resource
case class Backend(service: Option[ServiceType] = None, resource: Option[String] = None)
case class Path(path: String, backend: Backend, pathType: PathType = ImplementationSpecific)
case class HttpRule(paths: List[Path] = List())
case class Rule(host: Option[String], http: HttpRule)
case class TLS(hosts: List[String] = List(), secretName: Option[String] = None)

object PathType extends Enumeration {
type PathType = Value
val ImplementationSpecific, Exact, Prefix = Value
}

case class Spec(
backend: Option[Backend] = None,
rules: List[Rule] = List(),
tls: List[TLS] = List(),
ingressClassName: Option[String] = None)

case class Status(loadBalancer: Option[Status.LoadBalancer] = None)

object Status {
case class LoadBalancer(ingress: List[LoadBalancer.Ingress])
object LoadBalancer {
case class Ingress(ip: Option[String] = None, hostName: Option[String] = None)
}
}

// json formatters

import play.api.libs.functional.syntax._
import skuber.json.format._

implicit val ingressPortFmt: Format[Ingress.Port] = Json.format[Ingress.Port]

implicit val ingressServiceFmt: Format[Ingress.ServiceType] = (
(JsPath \ "name").format[String] and
(JsPath \ "port").format[Ingress.Port]
) (Ingress.ServiceType.apply _, i => (i.name, i.port))

implicit val ingressBackendFmt: Format[Ingress.Backend] = (
(JsPath \ "service").formatNullable[Ingress.ServiceType] and
(JsPath \ "resource").formatNullable[String]
) (Ingress.Backend.apply _, i => (i.service, i.resource))

implicit val ingressPathFmt: Format[Ingress.Path] = (
(JsPath \ "path").formatMaybeEmptyString() and
(JsPath \ "backend").format[Ingress.Backend] and
(JsPath \ "pathType").formatEnum(PathType, PathType.ImplementationSpecific.toString)
) (Ingress.Path.apply _, i => (i.path, i.backend, i.pathType))

implicit val ingressHttpRuledFmt: Format[Ingress.HttpRule] = Json.format[Ingress.HttpRule]
implicit val ingressRuleFmt : Format[Ingress.Rule] = Json.format[Ingress.Rule]
implicit val ingressTLSFmt : Format[Ingress.TLS] = Json.format[Ingress.TLS]


implicit val ingressSpecFormat: Format[Ingress.Spec] = (
(JsPath \ "defaultBackend").formatNullable[Ingress.Backend] and
(JsPath \ "rules").formatMaybeEmptyList[Ingress.Rule] and
(JsPath \ "tls").formatMaybeEmptyList[Ingress.TLS] and
(JsPath \ "ingressClassName").formatNullable[String]
) (Ingress.Spec.apply _, i => (i.backend, i.rules, i.tls, i.ingressClassName))


implicit val ingrlbingFormat: Format[Ingress.Status.LoadBalancer.Ingress] =
Json.format[Ingress.Status.LoadBalancer.Ingress]

implicit val ingrlbFormat: Format[Ingress.Status.LoadBalancer] =
(JsPath \ "ingress").formatMaybeEmptyList[Ingress.Status.LoadBalancer.Ingress].inmap(
ings => Ingress.Status.LoadBalancer(ings),
lb => lb.ingress
)

implicit val ingressStatusFormat: Format[Ingress.Status] = Json.format[Ingress.Status]

implicit lazy val ingressFormat: Format[Ingress] = (
objFormat and
(JsPath \ "spec").formatNullable[Ingress.Spec] and
(JsPath \ "status").formatNullable[Ingress.Status]
) (Ingress.apply _, i => (i.kind, i.apiVersion, i.metadata, i.spec, i.status))

implicit val ingressListFmt: Format[IngressList] = ListResourceFormat[Ingress]

}
9 changes: 9 additions & 0 deletions client/src/main/scala/skuber/networking/v1/package.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package skuber.networking

import skuber.ListResource

package object v1 {
val ingressAPIVersion = "networking.k8s.io/v1"

type IngressList = ListResource[Ingress]
}
Loading