All Downloads are FREE. Search and download functionalities are using the official Maven repository.

plugins.jobs.kubernetes.config.scala Maven / Gradle / Ivy

The newest version!
package otoroshi.plugins.jobs.kubernetes

import java.io.File
import java.nio.file.Files
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import otoroshi.env.Env
import otoroshi.script._
import otoroshi.utils.JsonPathValidator
import otoroshi.utils.syntax.implicits._
import otoroshi.utils.yaml.Yaml
import play.api.libs.json._

import java.nio.charset.StandardCharsets
import java.util.Base64
import scala.concurrent.ExecutionContext
import scala.util.Try

case class KubernetesConfig(
    endpoint: String,
    token: Option[String],
    userPassword: Option[String],
    caCert: Option[String],
    clientCert: Option[String],
    clientCertKey: Option[String],
    kubeLeader: Boolean,
    trust: Boolean,
    watch: Boolean,
    namespaces: Seq[String],
    namespacesLabels: Map[String, String],
    labels: Map[String, String],
    syncIntervalSeconds: Long,
    watchTimeoutSeconds: Int,
    watchGracePeriodSeconds: Int,
    ingresses: Boolean,
    ingressClasses: Seq[String],
    defaultGroup: String,
    ingressEndpointHostname: Option[String],
    ingressEndpointIp: Option[String],
    ingressEndpointPublishedService: Option[String],
    crds: Boolean,
    crdsOverride: Boolean,
    syncDaikokuApikeysOnly: Boolean,
    restartDependantDeployments: Boolean,
    useProxyState: Boolean,
    mutatingWebhookName: String,
    validatingWebhookName: String,
    image: Option[String],
    meshDomain: String,
    kubeSystemNamespace: String,
    otoroshiServiceName: String,
    otoroshiNamespace: String,
    clusterDomain: String,
    coreDnsEnv: Option[String],
    coreDnsConfigMapName: String,
    coreDnsDeploymentName: String,
    corednsPort: Int,
    coreDnsIntegration: Boolean,
    coreDnsIntegrationDryRun: Boolean,
    coreDnsAzure: Boolean,
    openshiftDnsOperatorIntegration: Boolean,
    openshiftDnsOperatorCleanup: Boolean,
    openshiftDnsOperatorCleanupNames: Seq[String],
    openshiftDnsOperatorCleanupDomains: Seq[String],
    openshiftDnsOperatorCoreDnsNamespace: String,
    openshiftDnsOperatorCoreDnsName: String,
    openshiftDnsOperatorCoreDnsPort: Int,
    kubeDnsOperatorIntegration: Boolean,
    kubeDnsOperatorCoreDnsNamespace: String,
    kubeDnsOperatorCoreDnsName: String,
    kubeDnsOperatorCoreDnsPort: Int,
    connectionTimeout: Long,
    idleTimeout: Long,
    callAndStreamTimeout: Long,
    triggerKey: Option[String],
    triggerHost: Option[String],
    triggerPath: Option[String],
    templates: JsObject
)

object KubernetesConfig {
  import collection.JavaConverters._
  def theConfig(ctx: ContextWithConfig)(implicit env: Env, ec: ExecutionContext): KubernetesConfig = {
    val globalConfig = env.datastores.globalConfigDataStore.latest()(env.otoroshiExecutionContext, env)
    val conf         = ctx
      .configForOpt("KubernetesConfig")
      .orElse((globalConfig.scripts.jobConfig \ "KubernetesConfig").asOpt[JsValue])
      .orElse((globalConfig.plugins.config \ "KubernetesConfig").asOpt[JsValue])
      .getOrElse(Json.obj())
    conf match {
      case JsArray(values)                                                              => {
        val context = Json.obj(
          "env"      -> globalConfig.env,
          "instance" -> env.configurationJson.select("otoroshi").select("instance").asValue
        )
        val cfg     = values
          .find { value =>
            value.select("predicates").asOpt[Seq[JsObject]] match {
              case None             => false
              case Some(predicates) => {
                val validators =
                  predicates.map(v => JsonPathValidator.format.reads(v)).collect { case JsSuccess(value, _) => value }
                validators.forall(_.validate(context))
              }
            }
          }
          .getOrElse {
            throw new RuntimeException("Unable to read kubernetes config on this instance !")
          }
        theConfig(cfg)
      }
      case obj @ JsObject(_) if obj.select("predicates").asOpt[Seq[JsObject]].isDefined => {
        obj.select("predicates").asOpt[Seq[JsObject]] match {
          case None             => theConfig(obj)
          case Some(predicates) => {
            val validators =
              predicates.map(v => JsonPathValidator.format.reads(v)).collect { case JsSuccess(value, _) => value }
            val context    = Json.obj(
              "env"      -> globalConfig.env,
              "instance" -> env.configurationJson.select("otoroshi").select("instance").asValue
            )
            if (validators.forall(_.validate(context))) {
              theConfig(obj)
            } else {
              throw new RuntimeException("Unable to read kubernetes config on this instance !")
            }
          }
        }
      }
      case JsObject(_)                                                                  => theConfig(conf)
      case _                                                                            => theConfig(conf)
    }

  }
  def theConfig(conf: JsValue)(implicit _env: Env, ec: ExecutionContext): KubernetesConfig = {
    sys.env.get("KUBECONFIG") match {
      case Some(configPath) => {
        val configContent         = Files.readAllLines(new File(configPath).toPath).asScala.mkString("\n").trim()
        // val yamlReader = new ObjectMapper(new YAMLFactory())
        // val obj = yamlReader.readValue(configContent, classOf[Object])
        // val jsonWriter = new ObjectMapper()
        // val json = Json.parse(jsonWriter.writeValueAsString(obj))
        val json                  = Yaml.parse(configContent).get
        val currentContextName    = (json \ "current-context").as[String]
        val currentContextUser    = (json \ "contexts")
          .as[JsArray]
          .value
          .find(v => (v \ "name").as[String] == currentContextName)
          .get
          .\("context")
          .\("user")
          .as[String]
        val currentContextCluster = (json \ "contexts")
          .as[JsArray]
          .value
          .find(v => (v \ "name").as[String] == currentContextName)
          .get
          .\("context")
          .\("cluster")
          .as[String]
        KubernetesConfig(
          trust = (conf \ "trust").asOpt[Boolean].getOrElse(false),
          endpoint = (json \ "clusters")
            .as[JsArray]
            .value
            .find(v => (v \ "name").as[String] == currentContextCluster)
            .map { defaultUser =>
              (defaultUser \ "cluster" \ "server").as[String]
            }
            .getOrElse(
              (conf \ "endpoint").asOpt[String].getOrElse {
                val host = sys.env("KUBERNETES_SERVICE_HOST")
                val port = sys.env("KUBERNETES_SERVICE_PORT")
                s"https://$host:$port"
              }
            ),
          token = None,
          clientCert =
            (json \ "users").as[JsArray].value.find(v => (v \ "name").as[String] == currentContextUser).flatMap {
              defaultUser =>
                defaultUser
                  .select("user")
                  .select("client-certificate-data")
                  .asOpt[String]
                  .map(v => new String(Base64.getDecoder.decode(v), StandardCharsets.UTF_8))
            },
          clientCertKey =
            (json \ "users").as[JsArray].value.find(v => (v \ "name").as[String] == currentContextUser).flatMap {
              defaultUser =>
                defaultUser
                  .select("user")
                  .select("client-key-data")
                  .asOpt[String]
                  .map(v => new String(Base64.getDecoder.decode(v), StandardCharsets.UTF_8))
            },
          userPassword =
            (json \ "users").as[JsArray].value.find(v => (v \ "name").as[String] == currentContextUser).flatMap {
              defaultUser =>
                for {
                  username <- (defaultUser \ "user" \ "username").asOpt[String]
                  password <- (defaultUser \ "user" \ "password").asOpt[String]
                } yield s"$username:$password"
            },
          caCert =
            (json \ "clusters").as[JsArray].value.find(v => (v \ "name").as[String] == currentContextCluster).map {
              defaultUser =>
                {
                  val base64Cert = (defaultUser \ "cluster" \ "certificate-authority-data").as[String]
                  val cert       = new String(Base64.getDecoder.decode(base64Cert), StandardCharsets.UTF_8)
                  cert
                }
            },
          namespaces = (conf \ "namespaces").asOpt[Seq[String]].filter(_.nonEmpty).getOrElse(Seq("*")),
          namespacesLabels = (conf \ "namespacesLabels").asOpt[Map[String, String]].getOrElse(Map.empty),
          labels = (conf \ "labels").asOpt[Map[String, String]].getOrElse(Map.empty),
          ingressClasses = (conf \ "ingressClasses")
            .asOpt[Seq[String]]
            .orElse((conf \ "ingressClass").asOpt[String].map(v => Seq(v)))
            .getOrElse(Seq("otoroshi")), // can be *
          defaultGroup = (conf \ "defaultGroup").asOpt[String].getOrElse("default"),
          ingressEndpointHostname = (conf \ "ingressEndpointHostname").asOpt[String],
          ingressEndpointIp = (conf \ "ingressEndpointIp").asOpt[String],
          ingressEndpointPublishedService = (conf \ "ingressEndpointPublishedServices").asOpt[String],
          coreDnsIntegration = (conf \ "coreDnsIntegration").asOpt[Boolean].getOrElse(false),
          coreDnsIntegrationDryRun = (conf \ "coreDnsIntegrationDryRun").asOpt[Boolean].getOrElse(false),
          coreDnsAzure = (conf \ "coreDnsAzure").asOpt[Boolean].getOrElse(false),
          ingresses = (conf \ "ingresses").asOpt[Boolean].getOrElse(true),
          crds = (conf \ "crds").asOpt[Boolean].getOrElse(true),
          crdsOverride = (conf \ "crdsOverride").asOpt[Boolean].getOrElse(false),
          kubeLeader = (conf \ "kubeLeader").asOpt[Boolean].getOrElse(false),
          restartDependantDeployments = (conf \ "restartDependantDeployments").asOpt[Boolean].getOrElse(false),
          useProxyState = (conf \ "useProxyState").asOpt[Boolean].getOrElse(false),
          watch = (conf \ "watch").asOpt[Boolean].getOrElse(true),
          syncDaikokuApikeysOnly = (conf \ "syncDaikokuApikeysOnly").asOpt[Boolean].getOrElse(false),
          triggerKey = (conf \ "triggerKey").asOpt[String],
          triggerHost = (conf \ "triggerHost").asOpt[String],
          triggerPath = (conf \ "triggerPath").asOpt[String],
          templates = (conf \ "templates").asOpt[JsObject].getOrElse(Json.obj()),
          kubeSystemNamespace = (conf \ "kubeSystemNamespace").asOpt[String].getOrElse("kube-system"),
          coreDnsConfigMapName = (conf \ "coreDnsConfigMapName").asOpt[String].getOrElse("coredns"),
          coreDnsDeploymentName = (conf \ "coreDnsDeploymentName").asOpt[String].getOrElse("coredns"),
          otoroshiServiceName = (conf \ "otoroshiServiceName").asOpt[String].getOrElse("otoroshi-service"),
          otoroshiNamespace = (conf \ "otoroshiNamespace").asOpt[String].getOrElse("otoroshi"),
          corednsPort = (conf \ "corednsPort").asOpt[Int].getOrElse(53),
          clusterDomain = (conf \ "clusterDomain").asOpt[String].getOrElse("cluster.local"),
          syncIntervalSeconds = (conf \ "syncIntervalSeconds").asOpt[Long].getOrElse(60L),
          coreDnsEnv = (conf \ "coreDnsEnv").asOpt[String].filterNot(_.trim.isEmpty),
          watchTimeoutSeconds = (conf \ "watchTimeoutSeconds").asOpt[Int].getOrElse(60),
          watchGracePeriodSeconds = (conf \ "watchGracePeriodSeconds").asOpt[Int].getOrElse(5),
          mutatingWebhookName =
            (conf \ "mutatingWebhookName").asOpt[String].getOrElse("otoroshi-admission-webhook-injector"),
          validatingWebhookName =
            (conf \ "validatingWebhookName").asOpt[String].getOrElse("otoroshi-admission-webhook-validation"),
          image = (conf \ "image").asOpt[String].filter(_.trim.nonEmpty),
          meshDomain = (conf \ "meshDomain").asOpt[String].filter(_.trim.nonEmpty).getOrElse("otoroshi.mesh"),
          openshiftDnsOperatorIntegration = (conf \ "openshiftDnsOperatorIntegration").asOpt[Boolean].getOrElse(false),
          openshiftDnsOperatorCoreDnsNamespace =
            (conf \ "openshiftDnsOperatorCoreDnsNamespace").asOpt[String].getOrElse("otoroshi"),
          openshiftDnsOperatorCoreDnsName =
            (conf \ "openshiftDnsOperatorCoreDnsName").asOpt[String].getOrElse("otoroshi-dns"),
          openshiftDnsOperatorCoreDnsPort = (conf \ "openshiftDnsOperatorCoreDnsPort").asOpt[Int].getOrElse(5353),
          openshiftDnsOperatorCleanup = (conf \ "openshiftDnsOperatorCleanup").asOpt[Boolean].getOrElse(false),
          openshiftDnsOperatorCleanupNames =
            (conf \ "openshiftDnsOperatorCleanupNames").asOpt[Seq[String]].getOrElse(Seq.empty),
          openshiftDnsOperatorCleanupDomains =
            (conf \ "openshiftDnsOperatorCleanupDomains").asOpt[Seq[String]].getOrElse(Seq.empty),
          kubeDnsOperatorIntegration = (conf \ "kubetDnsOperatorIntegration").asOpt[Boolean].getOrElse(false),
          kubeDnsOperatorCoreDnsNamespace =
            (conf \ "kubetDnsOperatorCoreDnsNamespace").asOpt[String].getOrElse("otoroshi"),
          kubeDnsOperatorCoreDnsName = (conf \ "kubetDnsOperatorCoreDnsName").asOpt[String].getOrElse("otoroshi-dns"),
          kubeDnsOperatorCoreDnsPort = (conf \ "kubetDnsOperatorCoreDnsPort").asOpt[Int].getOrElse(5353),
          connectionTimeout = conf.select("connectionTimeout").asOpt[Long].getOrElse(5000L),
          idleTimeout = conf.select("idleTimeout").asOpt[Long].getOrElse(30000L),
          callAndStreamTimeout = conf.select("callAndStreamTimeout").asOpt[Long].getOrElse(30000L)
        )
      }
      case None             => {
        KubernetesConfig(
          trust = (conf \ "trust").asOpt[Boolean].getOrElse(false),
          endpoint = (conf \ "endpoint").asOpt[String].getOrElse {
            val host = sys.env("KUBERNETES_SERVICE_HOST")
            val port = sys.env("KUBERNETES_SERVICE_PORT")
            s"https://$host:$port"
          },
          token = (conf \ "token")
            .asOpt[String]
            .orElse(
              Try(
                Files
                  .readAllLines(new File("/var/run/secrets/kubernetes.io/serviceaccount/token").toPath)
                  .asScala
                  .mkString("\n")
                  .trim()
              ).toOption
            ),
          userPassword = (conf \ "userPassword").asOpt[String],
          clientCert = (conf \ "clientCert").asOpt[String],
          clientCertKey = (conf \ "clientCertKey").asOpt[String],
          caCert = (conf \ "cert")
            .asOpt[String]
            .orElse((conf \ "certPath").asOpt[String].map { path =>
              Files.readAllLines(new File(path).toPath).asScala.mkString("\n").trim()
            })
            .orElse(
              new File("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt").some
                .filter(_.exists())
                .map(f => Files.readAllLines(f.toPath).asScala.mkString("\n").trim())
            ),
          namespaces = (conf \ "namespaces").asOpt[Seq[String]].filter(_.nonEmpty).getOrElse(Seq("*")),
          namespacesLabels = (conf \ "namespacesLabels").asOpt[Map[String, String]].getOrElse(Map.empty),
          labels = (conf \ "labels").asOpt[Map[String, String]].getOrElse(Map.empty),
          ingressClasses = (conf \ "ingressClasses")
            .asOpt[Seq[String]]
            .orElse((conf \ "ingressClass").asOpt[String].map(v => Seq(v)))
            .getOrElse(Seq("otoroshi")), // can be *
          defaultGroup = (conf \ "defaultGroup").asOpt[String].getOrElse("default"),
          ingressEndpointHostname = (conf \ "ingressEndpointHostname").asOpt[String],
          ingressEndpointIp = (conf \ "ingressEndpointIp").asOpt[String],
          ingressEndpointPublishedService = (conf \ "ingressEndpointPublishedServices").asOpt[String],
          ingresses = (conf \ "ingresses").asOpt[Boolean].getOrElse(true),
          coreDnsIntegration = (conf \ "coreDnsIntegration").asOpt[Boolean].getOrElse(false),
          coreDnsIntegrationDryRun = (conf \ "coreDnsIntegrationDryRun").asOpt[Boolean].getOrElse(false),
          coreDnsAzure = (conf \ "coreDnsAzure").asOpt[Boolean].getOrElse(false),
          crds = (conf \ "crds").asOpt[Boolean].getOrElse(true),
          crdsOverride = (conf \ "crdsOverride").asOpt[Boolean].getOrElse(false),
          kubeLeader = (conf \ "kubeLeader").asOpt[Boolean].getOrElse(false),
          restartDependantDeployments = (conf \ "restartDependantDeployments").asOpt[Boolean].getOrElse(false),
          useProxyState = (conf \ "useProxyState").asOpt[Boolean].getOrElse(false),
          watch = (conf \ "watch").asOpt[Boolean].getOrElse(true),
          syncDaikokuApikeysOnly = (conf \ "syncDaikokuApikeysOnly").asOpt[Boolean].getOrElse(false),
          triggerKey = (conf \ "triggerKey").asOpt[String],
          triggerHost = (conf \ "triggerHost").asOpt[String],
          triggerPath = (conf \ "triggerPath").asOpt[String],
          templates = (conf \ "templates").asOpt[JsObject].getOrElse(Json.obj()),
          kubeSystemNamespace = (conf \ "kubeSystemNamespace").asOpt[String].getOrElse("kube-system"),
          coreDnsConfigMapName = (conf \ "coreDnsConfigMapName").asOpt[String].getOrElse("coredns"),
          coreDnsDeploymentName = (conf \ "coreDnsDeploymentName").asOpt[String].getOrElse("coredns"),
          otoroshiServiceName = (conf \ "otoroshiServiceName").asOpt[String].getOrElse("otoroshi-service"),
          otoroshiNamespace = (conf \ "otoroshiNamespace").asOpt[String].getOrElse("otoroshi"),
          corednsPort = (conf \ "corednsPort").asOpt[Int].getOrElse(53),
          clusterDomain = (conf \ "clusterDomain").asOpt[String].getOrElse("cluster.local"),
          syncIntervalSeconds = (conf \ "syncIntervalSeconds").asOpt[Long].getOrElse(60L),
          coreDnsEnv = (conf \ "coreDnsEnv").asOpt[String].filterNot(_.trim.isEmpty),
          watchTimeoutSeconds = (conf \ "watchTimeoutSeconds").asOpt[Int].getOrElse(60),
          watchGracePeriodSeconds = (conf \ "watchGracePeriodSeconds").asOpt[Int].getOrElse(5),
          mutatingWebhookName =
            (conf \ "mutatingWebhookName").asOpt[String].getOrElse("otoroshi-admission-webhook-injector"),
          validatingWebhookName =
            (conf \ "validatingWebhookName").asOpt[String].getOrElse("otoroshi-admission-webhook-validation"),
          image = (conf \ "image").asOpt[String].filter(_.trim.nonEmpty),
          meshDomain = (conf \ "meshDomain").asOpt[String].filter(_.trim.nonEmpty).getOrElse("otoroshi.mesh"),
          openshiftDnsOperatorIntegration = (conf \ "openshiftDnsOperatorIntegration").asOpt[Boolean].getOrElse(false),
          openshiftDnsOperatorCoreDnsNamespace =
            (conf \ "openshiftDnsOperatorCoreDnsNamespace").asOpt[String].getOrElse("otoroshi"),
          openshiftDnsOperatorCoreDnsName =
            (conf \ "openshiftDnsOperatorCoreDnsName").asOpt[String].getOrElse("otoroshi-dns"),
          openshiftDnsOperatorCoreDnsPort = (conf \ "openshiftDnsOperatorCoreDnsPort").asOpt[Int].getOrElse(5353),
          openshiftDnsOperatorCleanup = (conf \ "openshiftDnsOperatorCleanup").asOpt[Boolean].getOrElse(false),
          openshiftDnsOperatorCleanupNames =
            (conf \ "openshiftDnsOperatorCleanupNames").asOpt[Seq[String]].getOrElse(Seq.empty),
          openshiftDnsOperatorCleanupDomains =
            (conf \ "openshiftDnsOperatorCleanupDomains").asOpt[Seq[String]].getOrElse(Seq.empty),
          kubeDnsOperatorIntegration = (conf \ "kubetDnsOperatorIntegration").asOpt[Boolean].getOrElse(false),
          kubeDnsOperatorCoreDnsNamespace =
            (conf \ "kubetDnsOperatorCoreDnsNamespace").asOpt[String].getOrElse("otoroshi"),
          kubeDnsOperatorCoreDnsName = (conf \ "kubetDnsOperatorCoreDnsName").asOpt[String].getOrElse("otoroshi-dns"),
          kubeDnsOperatorCoreDnsPort = (conf \ "kubetDnsOperatorCoreDnsPort").asOpt[Int].getOrElse(5353),
          connectionTimeout = conf.select("connectionTimeout").asOpt[Long].getOrElse(5000L),
          idleTimeout = conf.select("idleTimeout").asOpt[Long].getOrElse(30000L),
          callAndStreamTimeout = conf.select("callAndStreamTimeout").asOpt[Long].getOrElse(30000L)
        )
      }
    }
  }
  def defaultConfig: JsObject = {
    Json.obj(
      "KubernetesConfig" -> Json.obj(
        "endpoint"                             -> "https://kube.cluster.dev",
        "token"                                -> "xxx",
        "userPassword"                         -> "user:password",
        "caCert"                               -> "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt",
        "trust"                                -> false,
        "namespaces"                           -> Json.arr("*"),
        "labels"                               -> Json.obj(),
        "namespacesLabels"                     -> Json.obj(),
        "ingressClasses"                       -> Json.arr("otoroshi"),
        "defaultGroup"                         -> "default",
        "ingresses"                            -> true,
        "crds"                                 -> true,
        "crdsOverride"                         -> false, // when enabled crds always win, we do not try to read what's in datastore and merge
        "coreDnsIntegration"                   -> false,
        "coreDnsIntegrationDryRun"             -> false,
        "coreDnsAzure"                         -> false,
        "kubeLeader"                           -> false,
        "restartDependantDeployments"          -> true,
        "useProxyState"                        -> false,
        "watch"                                -> true,
        "syncDaikokuApikeysOnly"               -> false,
        "kubeSystemNamespace"                  -> "kube-system",
        "coreDnsConfigMapName"                 -> "coredns",
        "coreDnsDeploymentName"                -> "coredns",
        "corednsPort"                          -> 53,
        "otoroshiServiceName"                  -> "otoroshi-service",
        "otoroshiNamespace"                    -> "otoroshi",
        "clusterDomain"                        -> "cluster.local",
        "syncIntervalSeconds"                  -> 60,
        "coreDnsEnv"                           -> JsNull,
        "watchTimeoutSeconds"                  -> 60,
        "watchGracePeriodSeconds"              -> 5,
        "mutatingWebhookName"                  -> "otoroshi-admission-webhook-injector",
        "validatingWebhookName"                -> "otoroshi-admission-webhook-validation",
        "meshDomain"                           -> "otoroshi.mesh",
        "openshiftDnsOperatorIntegration"      -> false,
        "openshiftDnsOperatorCoreDnsNamespace" -> "otoroshi",
        "openshiftDnsOperatorCoreDnsName"      -> "otoroshi-dns",
        "openshiftDnsOperatorCoreDnsPort"      -> 5353,
        "kubeDnsOperatorIntegration"           -> false,
        "kubeDnsOperatorCoreDnsNamespace"      -> "otoroshi",
        "kubeDnsOperatorCoreDnsName"           -> "otoroshi-dns",
        "kubeDnsOperatorCoreDnsPort"           -> 5353,
        "connectionTimeout"                    -> 5000,
        "idleTimeout"                          -> 30000,
        "callAndStreamTimeout"                 -> 30000,
        "templates"                            -> Json.obj(
          "service-group"      -> Json.obj(),
          "service-descriptor" -> Json.obj(),
          "apikeys"            -> Json.obj(),
          "global-config"      -> Json.obj(),
          "jwt-verifier"       -> Json.obj(),
          "tcp-service"        -> Json.obj(),
          "certificate"        -> Json.obj(),
          "auth-module"        -> Json.obj(),
          "script"             -> Json.obj(),
          "data-exporters"     -> Json.obj(),
          "organizations"      -> Json.obj(),
          "teams"              -> Json.obj(),
          "admins"             -> Json.obj(),
          "webhooks"           -> Json.obj()
        )
      )
    )
  }
  def configFlow: Seq[String] = {
    Seq(
      "<<>>job settings",
      "namespaces",
      "namespacesLabels",
      "labels",
      "kubeLeader",
      "watch",
      "syncIntervalSeconds",
      "watchTimeoutSeconds",
      "watchGracePeriodSeconds",
      ">>>ingress controller",
      "ingresses",
      "ingressClasses",
      "ingressEndpointHostname",
      "ingressEndpointIp",
      "ingressEndpointPublishedService",
      "defaultGroup",
      ">>>CRDs",
      "crds",
      "syncDaikokuApikeysOnly",
      "restartDependantDeployments",
      "useProxyState",
      ">>>webhooks",
      "validatingWebhookName",
      "mutatingWebhookName",
      "image",
      ">>>DNS & service mesh",
      "meshDomain",
      "kubeSystemNamespace",
      "otoroshiServiceName",
      "otoroshiNamespace",
      "clusterDomain",
      ">>>coredns integration",
      "coreDnsIntegration",
      "coreDnsIntegrationDryRun",
      "coreDnsAzure",
      "coreDnsConfigMapName",
      "coreDnsDeploymentName",
      "corednsPort",
      "coreDnsEnv",
      ">>>openshift DNS operator",
      "openshiftDnsOperatorIntegration",
      "openshiftDnsOperatorCleanup",
      "openshiftDnsOperatorCleanupNames",
      "openshiftDnsOperatorCleanupDomains",
      "openshiftDnsOperatorCoreDnsNamespace",
      "openshiftDnsOperatorCoreDnsName",
      "openshiftDnsOperatorCoreDnsPort",
      ">>>legacy kubernetes DNS",
      "kubeDnsOperatorIntegration",
      "kubeDnsOperatorCoreDnsNamespace",
      "kubeDnsOperatorCoreDnsName",
      "kubeDnsOperatorCoreDnsPort",
      ">>>client settings",
      "connectionTimeout",
      "idleTimeout",
      "callAndStreamTimeout"
    )
  }

  private def makeFormField(
      name: String,
      typ: String,
      label: String,
      help: Option[String] = None,
      more: JsObject = Json.obj()
  ): JsObject = {
    val h     = help.getOrElse("...")
    val props = Json.obj(
      "label" -> label,
      "help"  -> h
    ) ++ more
    Json.obj(
      name -> Json.obj(
        "type"  -> typ,
        "props" -> props
      )
    )
  }

  def configSchema: Option[JsObject] = Some(
    Json.obj()
    ++ makeFormField(
      "trust",
      "bool",
      "Trust Kube CA",
      "Do you want to trust the kubernetes cluster issued CA for TLS connections".some
    )
    ++ makeFormField(
      "endpoint",
      "string",
      "Kube API endpoint",
      "The http URL to access kubernetes api server (optional, will look for $KUBERNETE_HOST and $KUBERNETES_PORT if not provided)".some
    )
    ++ makeFormField(
      "token",
      "string",
      "Kube API access token",
      "The jwt token to access kubernetes api server (optional, will look for /var/run/secrets/kubernetes.io/serviceaccount/token if not provided)".some
    )
    ++ makeFormField(
      "userPassword",
      "string",
      "Kube API user/password",
      "Base64 encoded user password tuple to access kubernetes api server (optional)".some
    )
    ++ makeFormField(
      "caCert",
      "string",
      "Kube API CA cert",
      "Kubernetes api server CA cert (optional, will look for /var/run/secrets/kubernetes.io/serviceaccount/ca.crt if not provided)".some
    )

    ++ makeFormField("namespaces", "array", "Kube namespaces", "Kubernetes namespaces that will be query".some)
    ++ makeFormField(
      "namespacesLabels",
      "object",
      "Kube namespace labels",
      "Kubernetes namespaces with those labels that will be query".some
    )
    ++ makeFormField("labels", "object", "Kube labels", "Kubernetes entities with those labels will be query".some)
    ++ makeFormField(
      "kubeLeader",
      "bool",
      "Use kube leader",
      "If enabled, otoroshi will delegate job running leader to kubernetes leader".some
    )
    ++ makeFormField(
      "syncIntervalSeconds",
      "number",
      "Sync interval",
      "Number of seconds between syncs".some,
      more = Json.obj("suffix" -> "seconds")
    )
    ++ makeFormField(
      "watch",
      "bool",
      "Watch kube events",
      "If enabled, will watch kubernetes events and trigger sync according to it".some
    )
    ++ makeFormField(
      "watchTimeoutSeconds",
      "number",
      "Watch timeout",
      "Number of seconds before watch timeout".some,
      more = Json.obj("suffix" -> "seconds")
    )
    ++ makeFormField(
      "watchGracePeriodSeconds",
      "number",
      "Watch grace period",
      "Number of seconds for collapsing watch events".some,
      more = Json.obj("suffix" -> "seconds")
    )

    ++ makeFormField("ingresses", "bool", "Enable", "Enable ingress controller".some)
    ++ makeFormField(
      "ingressClasses",
      "array",
      "Ingress classes",
      "Ingress classes watched by otoroshi ingress controller".some
    )
    ++ makeFormField(
      "defaultGroup",
      "string",
      "Default group",
      "Otoroshi groups where ingress services will be created".some,
      more = Json.obj("placeholder" -> "default")
    )

    ++ makeFormField("crds", "bool", "Enabled", "Enable Otoroshi CRDs".some)
    ++ makeFormField(
      "syncDaikokuApikeysOnly",
      "bool",
      "Sync only daikoku apikeys",
      "If enabled, only the apikeys CRDs with daikoku integration token will be synced".some
    )
    ++ makeFormField(
      "restartDependantDeployments",
      "bool",
      "Restart deployments",
      "If enabled, deployments dependant to otoroshi managed secrets (apikeys, certs) will be automatically restarted as secrets are updated".some
    )
    ++ makeFormField(
      "useProxyState",
      "bool",
      "Use proxy state",
      "If enabled, the sync between entities coming from kube and entity coming from datastore will use proxy state data instead of datastore access. Should save some cpu/io/ram.".some
    )
    ++ makeFormField(
      "mutatingWebhookName",
      "string",
      "Sidecar webhook name",
      "If you want to use otoroshi sidecars, you need to specify the name of the dedicated mutating webhook".some,
      more = Json.obj("placeholder" -> "otoroshi-admission-webhook-injector")
    )
    ++ makeFormField(
      "validatingWebhookName",
      "string",
      "Validation webhook name",
      "If you want to use kubectl validation, you need to specify the name of the dedicated validating webhook".some,
      more = Json.obj("placeholder" -> "otoroshi-admission-webhook-validation")
    )
    ++ makeFormField(
      "image",
      "string",
      "Sidecar image",
      "The docker image for the otoroshi injected sidecar".some,
      more = Json.obj("placeholder" -> "maif/otoroshi-sidecar:latest")
    )

    ++ makeFormField(
      "meshDomain",
      "string",
      "Mesh domain",
      "The domain used for service mesh".some,
      more = Json.obj("placeholder" -> "otoroshi.mesh")
    )
    ++ makeFormField(
      "kubeSystemNamespace",
      "string",
      "Kube system namespace",
      "The namespace containing coredns".some,
      more = Json.obj("placeholder" -> "kube-system")
    )
    ++ makeFormField(
      "otoroshiNamespace",
      "string",
      "Otoroshi namespace",
      "The namespace where otoroshi is deployed".some,
      more = Json.obj("placeholder" -> "otoroshi")
    )
    ++ makeFormField(
      "otoroshiServiceName",
      "string",
      "Otoroshi service",
      "The service name for otoroshi".some,
      more = Json.obj("placeholder" -> "otoroshi-service")
    )
    ++ makeFormField(
      "clusterDomain",
      "string",
      "Cluster domain",
      "The current kubernetes cluster domain".some,
      more = Json.obj("placeholder" -> "svc.cluster.local")
    )

    ++ makeFormField("coreDnsIntegration", "bool", "Coredns integration", "Auto register service mesh in coredns".some)
    ++ makeFormField("coreDnsIntegrationDryRun", "bool", "Dry run", "Just simulate integration".some)
    ++ makeFormField("coreDnsAzure", "bool", "AKS", "Use when running on AKS".some)
    ++ makeFormField(
      "coreDnsConfigMapName",
      "string",
      "Config map name",
      "The name of the coredns config-map".some,
      more = Json.obj("placeholder" -> "coredns")
    )
    ++ makeFormField(
      "coreDnsDeploymentName",
      "string",
      "Deployment name",
      "The name of the coredns deployment".some,
      more = Json.obj("placeholder" -> "coredns")
    )
    ++ makeFormField(
      "corednsPort",
      "number",
      "Coredns port",
      "The DNS port to expose service mesh regions".some,
      more = Json.obj("placeholder" -> "53")
    )
    ++ makeFormField("coreDnsEnv", "string", "Coredns env", "Preffix for meshDomain".some)

    ++ makeFormField(
      "openshiftDnsOperatorIntegration",
      "bool",
      "Openshift dns integration",
      "Auto register service mesh in openshift DNS operator".some
    )
    ++ makeFormField("openshiftDnsOperatorCleanup", "bool", "Cleanup", "Cleanup DNS operator".some)
    ++ makeFormField(
      "openshiftDnsOperatorCleanupNames",
      "array",
      "Cleanup names",
      "Cleanup DNS operator based on names".some,
      more = Json.obj("suffix" -> "regex")
    )
    ++ makeFormField(
      "openshiftDnsOperatorCleanupDomains",
      "array",
      "Cleanup domains",
      "Cleanup DNS operator based on domains".some,
      more = Json.obj("suffix" -> "regex")
    )
    ++ makeFormField(
      "openshiftDnsOperatorCoreDnsNamespace",
      "string",
      "DNS operator namespace",
      "DNS operator namespace".some,
      more = Json.obj("placeholder" -> "otoroshi")
    )
    ++ makeFormField(
      "openshiftDnsOperatorCoreDnsName",
      "string",
      "DNS operator name",
      "DNS operator name".some,
      more = Json.obj("placeholder" -> "otoroshi-dns")
    )
    ++ makeFormField(
      "openshiftDnsOperatorCoreDnsPort",
      "number",
      "DNS operator port number",
      "DNS operator port number".some,
      more = Json.obj("placeholder" -> "5353")
    )

    ++ makeFormField(
      "kubeDnsOperatorIntegration",
      "bool",
      "Kube dns integration",
      "Auto register service mesh in legacy kubedns".some
    )
    ++ makeFormField(
      "kubeDnsOperatorCoreDnsNamespace",
      "string",
      "Kube dns namespace",
      "Kube dns namespace".some,
      more = Json.obj("placeholder" -> "otoroshi")
    )
    ++ makeFormField(
      "kubeDnsOperatorCoreDnsName",
      "string",
      "Kube dns name",
      "Kube dns name".some,
      more = Json.obj("placeholder" -> "otoroshi-dns")
    )
    ++ makeFormField(
      "kubeDnsOperatorCoreDnsPort",
      "number",
      "Kube dns port number",
      "Kube dns port number".some,
      more = Json.obj("placeholder" -> "5353")
    )
  )
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy