Skip to content

Commit

Permalink
Upgrade to zio-config 4.0.0-RC16 (#519)
Browse files Browse the repository at this point in the history
* Upgrade to zio-config 4.0.0-RC16

* Updates to correct compile errors in mdoc

---------

Co-authored-by: ggavares <grant.gavares@oracle.com>
  • Loading branch information
gavares and ggavares authored Aug 6, 2023
1 parent b82c7fd commit c6c4879
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 136 deletions.
6 changes: 4 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ val scala213Version = "2.13.11"
val scala3Version = "3.3.0"

val zioVersion = "2.0.15"
val zioConfigVersion = "3.0.7"
val zioConfigVersion = "4.0.0-RC16"
val zioLoggingVersion = "2.1.13"
val sttpVersion = "3.8.16"
val zioNioVersion = "2.0.1"
Expand Down Expand Up @@ -63,6 +63,8 @@ lazy val client = Project("zio-k8s-client", file("zio-k8s-client"))
"dev.zio" %% "zio" % zioVersion,
"dev.zio" %% "zio-streams" % zioVersion,
"dev.zio" %% "zio-config" % zioConfigVersion,
"dev.zio" %% "zio-config-derivation" % zioConfigVersion,
"dev.zio" %% "zio-config-magnolia" % zioConfigVersion,
"dev.zio" %% "zio-nio" % zioNioVersion,
"dev.zio" %% "zio-process" % "0.7.2",
"dev.zio" %% "zio-prelude" % zioPreludeVersion,
Expand All @@ -74,9 +76,9 @@ lazy val client = Project("zio-k8s-client", file("zio-k8s-client"))
"io.circe" %% "circe-parser" % "0.14.5",
"io.circe" %% "circe-yaml" % "0.14.2",
"org.bouncycastle" % "bcpkix-jdk18on" % "1.75",
"dev.zio" %% "zio-config-typesafe" % zioConfigVersion % Test,
"dev.zio" %% "zio-test" % zioVersion % Test,
"dev.zio" %% "zio-test-sbt" % zioVersion % Test,
"dev.zio" %% "zio-config-typesafe" % zioConfigVersion % Test,
"com.softwaremill.sttp.client3" %% "slf4j-backend" % sttpVersion % Optional,
"com.softwaremill.sttp.client3" %% "async-http-client-backend-zio" % sttpVersion % Optional
),
Expand Down
30 changes: 18 additions & 12 deletions docs/overview/gettingstarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,20 +127,26 @@ val cluster = config >>> k8sCluster
```scala mdoc:silent:reset
import com.coralogix.zio.k8s.client.config._
import com.coralogix.zio.k8s.client.config.httpclient._
import com.typesafe.config.ConfigFactory
import zio.config.ConfigDescriptor
import com.coralogix.zio.k8s.client.model._
import zio.config._
import zio.config.typesafe._
import zio._

case class Config(k8s: K8sClusterConfig)

// Loading config from HOCON
val configDesc = ConfigDescriptor.nested("k8s")(clusterConfigDescriptor).to[Config]
val config = TypesafeConfig.fromTypesafeConfig[Config](ZIO.attempt(ConfigFactory.load.resolve), configDesc)
// Define a custom configuration class for your application
case class MyConfig(k8s: K8sClusterConfig)
object MyConfig {
val configDescriptor: zio.Config[MyConfig] = clusterConfigDescriptor.map(k8s => MyConfig(k8s))
val live = ZLayer.fromZIO(ZIO.config(configDescriptor))
val k8s = ZLayer.fromFunction { cfg: MyConfig => cfg.k8s }
}

// K8s configuration and client layers
val client = config.project(_.k8s) >>> k8sSttpClient()
val cluster = config.project(_.k8s) >>> k8sCluster
// Set the config provider for the ZIO runtime to load your typesafe config. Typically this is done by overriding
// `ZIOAppDefault.bootstrap` in the Main class of your project.
val bootstrap: ZLayer[Any, Nothing, Unit] =
zio.Runtime.setConfigProvider(TypesafeConfigProvider.fromResourcePath())

//create zio-k8s layers for use in your application
val k8sLayers = MyConfig.live >>> MyConfig.k8s ++ k8sCluster ++ k8sSttpClient()
```

and place the configuration in `application.conf`, for example:
Expand All @@ -167,7 +173,7 @@ k8s {

## Clients

The above created `client` and `cluster` modules can be fed to any of the `zio-k8s` **client modules**
The above created `k8sLayers` can be fed to any of the `zio-k8s` **client modules**
to access _Kubernetes_ resources. This is explained in details in the [resources](resources.md) section.

The following example demonstrates how to gain access to the _Kubernetes pods and config maps_:
Expand All @@ -176,7 +182,7 @@ The following example demonstrates how to gain access to the _Kubernetes pods an
import com.coralogix.zio.k8s.client.v1.configmaps.ConfigMaps
import com.coralogix.zio.k8s.client.v1.pods.Pods

val k8s = (cluster ++ client) >>> (Pods.live ++ ConfigMaps.live)
val k8s = k8sLayers >>> (Pods.live ++ ConfigMaps.live)
```

## Notes
Expand Down
Original file line number Diff line number Diff line change
@@ -1,130 +1,81 @@
package com.coralogix.zio.k8s.client.config

import sttp.model.Uri
import zio.config.ConfigDescriptor._
import zio.config._
import zio.Config.boolean
import zio.nio.file.Path
import zio.{ Chunk, Config }

/** Defines ZIO Config descriptors for all the configuration data types of zio-k8s
*/
trait Descriptors {
private val uri: ConfigDescriptor[Uri] =
string.transformOrFail(
s => Uri.parse(s),
(uri: Uri) => Right(uri.toString)
)

private val path: ConfigDescriptor[Path] =
string.transform(
s => Path(s),
(path: Path) => path.toString()
)

private val keySourceFromFile: ConfigDescriptor[KeySource] =
nested("path")(path).transformOrFailRight(
(s: Path) => KeySource.FromFile(s),
{
case KeySource.FromFile(path) => Right(path)
case _ => Left("Not a KeySource.FromFile")
}
)

private val keySourceFromBase64: ConfigDescriptor[KeySource] =
nested("base64")(string).transformOrFailRight(
(s: String) => KeySource.FromBase64(s),
{
case KeySource.FromBase64(base64) => Right(base64)
case _ => Left("Not a KeySource.FromBase64")
}
)

private val keySourceFromString: ConfigDescriptor[KeySource] =
nested("value")(string).transformOrFailRight(
(s: String) => KeySource.FromString(s),
{
case KeySource.FromString(value) => Right(value)
case _ => Left("Not a KeySource.FromString")
}
)
private val uri: Config[Uri] =
Config.string.mapOrFail { s =>
Uri.parse(s).left.map(err => Config.Error.InvalidData(Chunk.empty, err))
}

private val keySource: ConfigDescriptor[KeySource] =
keySourceFromFile <> keySourceFromString <> keySourceFromBase64
private val path: Config[Path] = Config.string.map(Path(_))

private val serviceAccountToken: ConfigDescriptor[K8sAuthentication] =
nested("serviceAccountToken")(keySource).transformOrFailRight(
(s: KeySource) => K8sAuthentication.ServiceAccountToken(s),
{
case K8sAuthentication.ServiceAccountToken(token) => Right(token)
case _ => Left("Not a K8sAuthentication.ServiceAccountToken")
}
)

private val basicAuth: ConfigDescriptor[K8sAuthentication] =
nested("basicAuth")(
string("username") zip string("password")
).transformOrFailRight(
{ case (username, password) => K8sAuthentication.BasicAuth(username, password) },
{
case K8sAuthentication.BasicAuth(username, password) => Right((username, password))
case _ => Left("Not a K8sAuthentication.BasicAuth")
}
)

private val clientCertificates: ConfigDescriptor[K8sAuthentication] =
nested("clientCertificates")(
nested("certificate")(keySource) zip nested("key")(keySource) zip string(
"password"
).optional
).transformOrFailRight(
{ case (certificate, key, password) =>
K8sAuthentication.ClientCertificates(certificate, key, password)
},
{
case K8sAuthentication.ClientCertificates(certificate, key, password) =>
Right((certificate, key, password))
case _ => Left("Not a K8sAuthentication.ClientCertificates")
}
)

private val k8sAuthentication: ConfigDescriptor[K8sAuthentication] =
serviceAccountToken <> basicAuth <> clientCertificates

private val insecureServerCertificate: ConfigDescriptor[K8sServerCertificate] =
boolean("insecure").transformOrFail(
{
case true => Right(K8sServerCertificate.Insecure)
case false => Left("Use insecure: true or secure")
},
{
case K8sServerCertificate.Insecure => Right(true)
case _ => Left("Not a K8sServerCertificate.Insecure")
private val keySourceFromFile: Config[KeySource] =
path.nested("path").map(p => KeySource.FromFile(p))

private val keySourceFromBase64: Config[KeySource] =
Config.string.nested("base64").map(s => KeySource.FromBase64(s))

private val keySourceFromString: Config[KeySource] =
Config.string.nested("value").map(s => KeySource.FromString(s))

private val keySource: Config[KeySource] =
keySourceFromFile orElse keySourceFromString orElse keySourceFromBase64

private val serviceAccountToken: Config[K8sAuthentication] =
keySource.nested("serviceAccountToken").map(ks => K8sAuthentication.ServiceAccountToken(ks))

private val basicAuth: Config[K8sAuthentication] =
(Config.string("username") zip Config.string("password")).nested("basicAuth") map {
case (username, password) => K8sAuthentication.BasicAuth(username, password)
}

private val clientCertificates: Config[K8sAuthentication] =
(keySource.nested("certificate") zip
keySource.nested("key") zip
Config.string("password").optional)
.nested("clientCertificates")
.map { case (cert, key, password) =>
K8sAuthentication.ClientCertificates(cert, key, password)
}
)

private val secureServerCertificate: ConfigDescriptor[K8sServerCertificate] =
nested("secure")(
nested("certificate")(keySource) zip boolean("disableHostnameVerification")
).transformOrFailRight(
{ case (cert, disableHostnameVerification) =>
private val k8sAuthentication: Config[K8sAuthentication] =
serviceAccountToken orElse basicAuth orElse clientCertificates

private val insecureServerCertificate: Config[K8sServerCertificate] =
boolean("insecure").mapOrFail {
case true => Right(K8sServerCertificate.Insecure)
case false => Left(Config.Error.InvalidData(Chunk.empty, "Use insecure: true or secure"))
}

private val secureServerCertificate: Config[K8sServerCertificate] =
(keySource.nested("certificate") zip Config.boolean("disableHostnameVerification"))
.nested("secure")
.map { case (cert, disableHostnameVerification) =>
K8sServerCertificate.Secure(cert, disableHostnameVerification)
},
{
case K8sServerCertificate.Secure(cert, disableHostnameVerification) =>
Right((cert, disableHostnameVerification))
case K8sServerCertificate.Insecure => Left("Not a K8sServerCertificate.Secure")
}
)

private val serverCertificate: ConfigDescriptor[K8sServerCertificate] =
insecureServerCertificate <> secureServerCertificate
private val serverCertificate: Config[K8sServerCertificate] =
insecureServerCertificate orElse secureServerCertificate

private val clientConfig: ConfigDescriptor[K8sClientConfig] =
(boolean("debug") zip serverCertificate).to[K8sClientConfig]
private val clientConfig: Config[K8sClientConfig] =
(boolean("debug") zip serverCertificate).map { case (debug, cert) =>
K8sClientConfig(debug, cert)
}

/** ZIO Config descriptor for [[K8sClusterConfig]]
*/
val clusterConfigDescriptor: ConfigDescriptor[K8sClusterConfig] =
(nested("host")(uri) zip nested("authentication")(k8sAuthentication) zip nested("client")(
clientConfig
)).to[K8sClusterConfig]
val clusterConfigDescriptor: Config[K8sClusterConfig] =
(uri.nested("host") zip
k8sAuthentication.nested("authentication") zip
clientConfig.nested("client"))
.map { case (uri, auth, client) =>
K8sClusterConfig(uri, auth, client)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import io.circe.yaml.parser._

import zio.nio.file.Path
import zio.nio.file.Files
import zio.{ IO, Task, ZIO }
import zio.{ IO, ZIO }

import java.nio.charset.StandardCharsets

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import sttp.capabilities.zio.ZioStreams
import sttp.client3.SttpBackend
import sttp.client3.asynchttpclient.zio._
import sttp.client3.logging.LoggingBackend
import sttp.client3.logging.slf4j.{ Slf4jLogger, Slf4jLoggingBackend }
import sttp.client3.logging.slf4j.Slf4jLogger
import zio._

/** HTTP client implementation based on the async-http-client-zio backend
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import sttp.capabilities.zio.ZioStreams
import sttp.client3.SttpBackend
import sttp.client3.httpclient.zio._
import sttp.client3.logging.LoggingBackend
import sttp.client3.logging.slf4j.{ Slf4jLogger, Slf4jLoggingBackend }
import sttp.client3.logging.slf4j.Slf4jLogger
import zio._

import java.net.http.HttpClient
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import io.circe.generic.semiauto.deriveDecoder
import io.circe.{ parser, Decoder }
import sttp.client3.UriContext
import sttp.model.Uri
import zio.config._
import zio.nio.file.Path
import zio.process.Command
import zio.{ Layer, RIO, Scope, System, Task, ZIO, ZLayer }
Expand Down Expand Up @@ -180,16 +179,15 @@ package object config extends Descriptors {
}
}

/** Layer producing a [[com.coralogix.zio.k8s.client.model.K8sCluster]] from a provided
* K8sClusterConfig
/** Layer producing a [[com.coralogix.zio.k8s.client.model.K8sCluster]] from a K8sClusterConfig
*
* This can be used to either set up from a configuration source with zio-config or provide the
* hostname and token programmatically for the Kubernetes client.
*/
val k8sCluster: ZLayer[K8sClusterConfig, Throwable, K8sCluster] =
ZLayer.scoped {
for {
config <- getConfig[K8sClusterConfig]
config <- ZIO.service[K8sClusterConfig]
result <- config.authentication match {
case K8sAuthentication.ServiceAccountToken(tokenSource) =>
loadKeyString(tokenSource).flatMap { token =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import com.coralogix.zio.k8s.client.config.K8sAuthentication.ServiceAccountToken
import com.coralogix.zio.k8s.client.config.KeySource.FromString
import io.circe.yaml.parser.parse
import sttp.client3._
import zio.config._
import zio.config.typesafe.TypesafeConfig
import zio.config.typesafe.TypesafeConfigProvider
import zio.nio.file.{ Files, Path }
import zio.test.{ assertCompletes, assertZIO, Assertion, Spec, TestEnvironment, ZIOSpecDefault }
import zio.{ Chunk, ZIO }
Expand Down Expand Up @@ -81,7 +80,7 @@ object ConfigSpec extends ZIOSpecDefault {
val clientConfigSpec: Spec[zio.test.TestEnvironment, Any] = test("load client config") {
// Loading config from HOCON
val loadConfig = ZIO.scoped {
TypesafeConfig.fromHoconString[Config](example1, configDesc).build.map(_.get)
TypesafeConfigProvider.fromHoconString(example1).load(configDesc)
}

assertZIO(loadConfig)(
Expand Down Expand Up @@ -144,8 +143,7 @@ object ConfigSpec extends ZIOSpecDefault {

case class Config(k8s: K8sClusterConfig)

val configDesc: ConfigDescriptor[Config] =
ConfigDescriptor.nested("k8s")(clusterConfigDescriptor).to[Config]
val configDesc: zio.Config[Config] = clusterConfigDescriptor.nested("k8s").map(Config)

val example1: String =
"""k8s {
Expand Down

0 comments on commit c6c4879

Please sign in to comment.