blob: 00d876e3ad2dbddeb9af5ee6c506e6789cd2173b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.openwhisk.core
import java.io.File
import akka.http.scaladsl.model.Uri.normalize
import org.apache.openwhisk.common.{Config, Logging}
import scala.io.Source
import scala.util.Try
/**
* A set of properties which might be needed to run a whisk microservice implemented
* in scala.
*
* @param requiredProperties a Map whose keys define properties that must be bound to
* a value, and whose values are default values. A null value in the Map means there is
* no default value specified, so it must appear in the properties file.
* @param optionalProperties a set of optional properties (which may not be defined).
* @param propertiesFile a File object, the whisk.properties file, which if given contains the property values.
* @param env an optional environment to initialize from.
*/
class WhiskConfig(requiredProperties: Map[String, String],
optionalProperties: Set[String] = Set.empty,
propertiesFile: File = null,
env: Map[String, String] = sys.env)(implicit logging: Logging)
extends Config(requiredProperties, optionalProperties)(env) {
/**
* Loads the properties as specified above.
*
* @return a pair which is the Map defining the properties, and a boolean indicating whether validation succeeded.
*/
override protected def getProperties() = {
val properties = super.getProperties()
if (!disableReadFromFile()) {
WhiskConfig.readPropertiesFromFile(properties, Option(propertiesFile) getOrElse (WhiskConfig.whiskPropertiesFile))
}
properties
}
private def disableReadFromFile() = java.lang.Boolean.getBoolean(WhiskConfig.disableWhiskPropsFileRead)
val servicePort = this(WhiskConfig.servicePort)
val dockerEndpoint = this(WhiskConfig.dockerEndpoint)
val dockerPort = this(WhiskConfig.dockerPort)
val wskApiHost: String = Try(
normalize(
s"${this(WhiskConfig.wskApiProtocol)}://${this(WhiskConfig.wskApiHostname)}:${this(WhiskConfig.wskApiPort)}"))
.getOrElse("")
val controllerBlackboxFraction = this.getAsDouble(WhiskConfig.controllerBlackboxFraction, 0.10)
val edgeHost = this(WhiskConfig.edgeHostName) + ":" + this(WhiskConfig.edgeHostApiPort)
val kafkaHosts = this(WhiskConfig.kafkaHostList)
val edgeHostName = this(WhiskConfig.edgeHostName)
val invokerHosts = this(WhiskConfig.invokerHostsList)
val zookeeperHosts = this(WhiskConfig.zookeeperHostList)
val dbPrefix = this(WhiskConfig.dbPrefix)
val mainDockerEndpoint = this(WhiskConfig.mainDockerEndpoint)
val runtimesManifest = this(WhiskConfig.runtimesManifest)
val actionInvokePerMinuteLimit = this(WhiskConfig.actionInvokePerMinuteLimit)
val actionInvokeConcurrentLimit = this(WhiskConfig.actionInvokeConcurrentLimit)
val triggerFirePerMinuteLimit = this(WhiskConfig.triggerFirePerMinuteLimit)
val actionSequenceLimit = this(WhiskConfig.actionSequenceMaxLimit)
val controllerSeedNodes = this(WhiskConfig.controllerSeedNodes)
val schedulerHost = this(WhiskConfig.schedulerHost)
val schedulerRpcPort = this(WhiskConfig.schedulerRpcPort)
val schedulerAkkaPort = this(WhiskConfig.schedulerAkkaPort)
}
object WhiskConfig {
val disableWhiskPropsFileRead = Config.prefix + "disable.whisks.props.file.read"
/**
* Reads a key from system environment as if it was part of WhiskConfig.
*/
def readFromEnv(key: String): Option[String] = sys.env.get(asEnvVar(key))
private def whiskPropertiesFile: File = {
def propfile(dir: String, recurse: Boolean = false): File =
if (dir != null) {
val base = new File(dir)
val file = new File(base, "whisk.properties")
if (file.exists())
file
else if (recurse)
propfile(base.getParent, true)
else null
} else null
val dir = sys.props.get("user.dir")
if (dir.isDefined) {
propfile(dir.get, true)
} else {
null
}
}
/**
* Reads a Map of key-value pairs from the environment (sys.env) -- store them in the
* mutable properties object.
*/
def readPropertiesFromFile(properties: scala.collection.mutable.Map[String, String], file: File)(
implicit logging: Logging) = {
if (file != null && file.exists) {
logging.info(this, s"reading properties from file $file")
val source = Source.fromFile(file)
try {
for (line <- source.getLines if line.trim != "") {
val parts = line.split('=')
if (parts.length >= 1) {
val p = parts(0).trim
val v = if (parts.length == 2) parts(1).trim else ""
if (properties.contains(p)) {
properties += p -> v
logging.debug(this, s"properties file set value for $p")
}
} else {
logging.warn(this, s"ignoring properties $line")
}
}
} finally {
source.close()
}
}
}
def asEnvVar(key: String): String = {
if (key != null)
key.replace('.', '_').toUpperCase
else null
}
val servicePort = "port"
val dockerPort = "docker.port"
val dockerEndpoint = "main.docker.endpoint"
val dbPrefix = "db.prefix"
// these are not private because they are needed
// in the invoker (they are part of the environment
// passed to the user container)
val edgeHostName = "edge.host"
val wskApiProtocol = "whisk.api.host.proto"
val wskApiPort = "whisk.api.host.port"
val wskApiHostname = "whisk.api.host.name"
val wskApiHost = Map(wskApiProtocol -> "https", wskApiPort -> 443.toString, wskApiHostname -> null)
val mainDockerEndpoint = "main.docker.endpoint"
val controllerBlackboxFraction = "controller.blackboxFraction"
val dbInstances = "db.instances"
val kafkaHostList = "kafka.hosts"
val zookeeperHostList = "zookeeper.hosts"
val edgeHostApiPort = "edge.host.apiport"
val invokerHostsList = "invoker.hosts"
val dbHostsList = "db.hostsList"
val edgeHost = Map(edgeHostName -> null, edgeHostApiPort -> null)
val invokerHosts = Map(invokerHostsList -> null)
val kafkaHosts = Map(kafkaHostList -> null)
val zookeeperHosts = Map(zookeeperHostList -> null)
val runtimesManifest = "runtimes.manifest"
val actionSequenceMaxLimit = "limits.actions.sequence.maxLength"
val actionInvokePerMinuteLimit = "limits.actions.invokes.perMinute"
val actionInvokeConcurrentLimit = "limits.actions.invokes.concurrent"
val triggerFirePerMinuteLimit = "limits.triggers.fires.perMinute"
val controllerSeedNodes = "akka.cluster.seed.nodes"
val schedulerHost = "whisk.scheduler.endpoints.host"
val schedulerRpcPort = "whisk.scheduler.endpoints.rpcPort"
val schedulerAkkaPort = "whisk.scheduler.endpoints.akkaPort"
}
object ConfigKeys {
val cluster = "whisk.cluster"
val loadbalancer = "whisk.loadbalancer"
val fraction = "whisk.fraction"
val buildInformation = "whisk.info"
val couchdb = "whisk.couchdb"
val cosmosdb = "whisk.cosmosdb"
val mongodb = "whisk.mongodb"
val kafka = "whisk.kafka"
val kafkaCommon = s"$kafka.common"
val kafkaProducer = s"$kafka.producer"
val kafkaConsumer = s"$kafka.consumer"
val kafkaTopics = s"$kafka.topics"
val kafkaTopicsPrefix = s"$kafkaTopics.prefix"
val kafkaTopicsUserEventPrefix = s"$kafkaTopics.user-event.prefix"
val memory = "whisk.memory"
val timeLimit = "whisk.time-limit"
val logLimit = "whisk.log-limit"
val concurrencyLimit = "whisk.concurrency-limit"
val activation = "whisk.activation"
val userEvents = "whisk.user-events"
val runtimes = "whisk.runtimes"
val runtimesWhitelists = s"$runtimes.whitelists"
val db = "whisk.db"
val docker = "whisk.docker"
val dockerClient = s"$docker.client"
val dockerContainerFactory = s"$docker.container-factory"
val standaloneDockerContainerFactory = s"$docker.standalone.container-factory"
val runc = "whisk.runc"
val runcTimeouts = s"$runc.timeouts"
val tracing = "whisk.tracing"
val containerFactory = "whisk.container-factory"
val containerArgs = s"$containerFactory.container-args"
val runtimesRegistry = s"$containerFactory.runtimes-registry"
val userImagesRegistry = s"$containerFactory.user-images-registry"
val containerPool = "whisk.container-pool"
val blacklist = "whisk.blacklist"
val kubernetes = "whisk.kubernetes"
val kubernetesTimeouts = s"$kubernetes.timeouts"
val transactions = "whisk.transactions"
val logStore = "whisk.logstore"
val splunk = s"$logStore.splunk"
val logStoreElasticSearch = s"$logStore.elasticsearch"
val mesos = "whisk.mesos"
val yarn = "whisk.yarn"
val containerProxy = "whisk.container-proxy"
val containerProxyTimeouts = s"$containerProxy.timeouts"
val containerProxyHealth = s"$containerProxy.action-health-check"
val containerProxyActivationErrorLogs = s"$containerProxy.log-activation-errors"
val s3 = "whisk.s3"
val query = "whisk.query-limit"
val execSizeLimit = "whisk.exec-size-limit"
val controller = s"whisk.controller"
val controllerActivation = s"$controller.activation"
val etcd = "whisk.etcd"
val etcdLeaseTimeout = "whisk.etcd.lease.timeout"
val etcdPoolThreads = "whisk.etcd.pool.threads"
val activationStore = "whisk.activation-store"
val elasticSearchActivationStore = s"$activationStore.elasticsearch"
val activationStoreWithFileStorage = s"$activationStore.with-file-storage"
val metrics = "whisk.metrics"
val featureFlags = "whisk.feature-flags"
val durationChecker = s"whisk.duration-checker"
val whiskConfig = "whisk.config"
val sharedPackageExecuteOnly = s"whisk.shared-packages-execute-only"
val swaggerUi = "whisk.swagger-ui"
val disableStoreResult = s"$activation.disable-store-result"
val unstoredLogsEnabled = s"$activation.unstored-logs-enabled"
val apacheClientConfig = "whisk.apache-client"
val parameterStorage = "whisk.parameter-storage"
val azBlob = "whisk.azure-blob"
val schedulerMaxPeek = "whisk.scheduler.max-peek"
val schedulerInProgressJobRetentionSecond = "whisk.scheduler.in-progress-job-retention"
val whiskClusterName = "whisk.cluster.name"
val dataManagementServiceRetryInterval = "whisk.scheduler.data-management-service.retryInterval"
}