Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
fb10ca5
Initial setup for standalone OpenWhisk
chetanmeh Jun 18, 2019
74538d9
Enable lean providers
chetanmeh Jun 18, 2019
9f3acbb
Add support for setting whisk properties from typesafe config
chetanmeh Jun 18, 2019
d58c5f1
Add support for configuring manifest
chetanmeh Jun 18, 2019
bcd48ba
Make MemoryArtifactStore work in singleton mode
chetanmeh Jun 18, 2019
e543afa
Allow bootstrapping default set of users
chetanmeh Jun 18, 2019
19e2c5e
Allow configuring server port
chetanmeh Jun 18, 2019
59e1191
Disable jar target
chetanmeh Jun 18, 2019
e4574eb
Make OS specific setting programatic
chetanmeh Jun 18, 2019
0237e54
Enable prometheus metrics by default
chetanmeh Jun 18, 2019
4716ac9
Fix the description
chetanmeh Jun 19, 2019
5d11c5d
Use WhiskerControl port 3233 as default!
chetanmeh Jun 20, 2019
13930eb
Allow disabling read of whisk.properties
chetanmeh Jun 20, 2019
03170d0
Ensure that MemoryStore is only created when needed
chetanmeh Jun 20, 2019
bf6b25f
Fetch logs via `docker logs` command on Mac
chetanmeh Jun 21, 2019
f988f45
Revert config support for MemoryArtifactStore for now
chetanmeh Jun 21, 2019
eb4eced
Rename the main class
chetanmeh Jun 21, 2019
dae96cb
Add a OpenWhisk cool banner
chetanmeh Jun 21, 2019
c7b72b2
Remove dependency on other uncomiited changes
chetanmeh Jun 21, 2019
32fdfde
Extract the cli based log store as a generic impl for all OS
chetanmeh Jun 21, 2019
ae22d17
Bound only to localhost interface and not 0.0.0.0 for better security
chetanmeh Jun 21, 2019
f795b88
Make it work on Windows too!!!
chetanmeh Jun 21, 2019
380c97c
Add blank line to make build going
chetanmeh Jun 21, 2019
6fe7888
Package the default runtimes.json
chetanmeh Jun 21, 2019
ff53e39
Change generated jar name
chetanmeh Jun 21, 2019
01e0041
Use custom transactionId for user bootstrap
chetanmeh Jun 21, 2019
c9d0d35
Add initial readme
chetanmeh Jun 21, 2019
d776f96
Base revision on content hash
chetanmeh Jun 22, 2019
39471e0
Fix whitespace
chetanmeh Jun 22, 2019
f11209d
Add build info details based on git commit
chetanmeh Jun 22, 2019
9e59f73
Purge Memory stores before start
chetanmeh Jun 22, 2019
7255cf9
Update readme with cli setup
chetanmeh Jun 22, 2019
18317d0
Add test to check if recreated doc with diff content has diff rev
chetanmeh Jun 22, 2019
59ac3f3
Move transform method to a utility class
chetanmeh Jun 22, 2019
1f99dc4
Readd bytesize import
chetanmeh Jun 22, 2019
ee3c3d2
Include log timestamps and filter till sentinel
chetanmeh Jun 23, 2019
dc5938b
Use host.docker.internal as api host for Mac and Windows
chetanmeh Jun 23, 2019
c833779
Enable colored logging
chetanmeh Jun 23, 2019
1fb514e
Add support for --verbose flag to enable debug logging easily
chetanmeh Jun 23, 2019
00e4576
Color transactionId and source also. Also support disabling color log…
chetanmeh Jun 23, 2019
89a8658
Make the banner colored
chetanmeh Jun 24, 2019
d3b2cb2
Expose extension point for format log message
chetanmeh Jun 24, 2019
f1f22ae
Api host name is now defined via system property
chetanmeh Jun 24, 2019
144fd62
Add a set of pre flight checks to confirm if OpenWhisk can run proper…
chetanmeh Jun 24, 2019
a75645c
Also check if docker is running
chetanmeh Jun 24, 2019
0931083
Update error message
chetanmeh Jun 24, 2019
6159470
standalone openwhisk dev
chetanmeh Jun 24, 2019
098e9cd
New StandaloneDockerContainerFactory which adapts as per OS
chetanmeh Jun 25, 2019
984cfa1
Revert "standalone openwhisk dev"
chetanmeh Jun 25, 2019
f4c07bc
Use warn for misconfigured wsk
chetanmeh Jun 25, 2019
5527f0e
Validate the files passed as argument to check if it exists
chetanmeh Jun 25, 2019
26532c4
Only do pull for images having `openwhisk` prefix. For local image ge…
chetanmeh Jun 25, 2019
0d2ca2a
Add ./gradlew :core:standalone:run command to run jar directly
chetanmeh Jun 25, 2019
fd292cd
Update the readme
chetanmeh Jun 25, 2019
31c4137
Add standalone target
chetanmeh Jun 25, 2019
31f0881
Use Spring boot default bootRun target to run the jar. Also copy the …
chetanmeh Jun 26, 2019
b3784c6
Make test run against standalone server
chetanmeh Jun 26, 2019
6f09fc0
Support disabling pull of standard images all together. Required for …
chetanmeh Jun 26, 2019
f3d57a3
Disable pause/resume support for non linux setups
chetanmeh Jun 26, 2019
828c90c
Pass on standalone jar path to test
chetanmeh Jun 26, 2019
6ae5f58
Disable launching the server if preexisting server provided
chetanmeh Jun 26, 2019
f368bfd
Print the wsk and docker cli version
chetanmeh Jun 26, 2019
add1fab
Update README with details on how to connect to db
chetanmeh Jun 26, 2019
0fda29a
Build standalone as part of docker dist so as to be used in test
chetanmeh Jun 26, 2019
a65b528
Increase time allowed for server to start to 30 secs and log logs upo…
chetanmeh Jun 26, 2019
5b99c6e
Enable verifySystemShutdown in Mesos tests
chetanmeh Jun 26, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,14 @@ class Config(requiredProperties: Map[String, String], optionalProperties: Set[St
*/
protected def getProperties(): scala.collection.mutable.Map[String, String] = {
val required = scala.collection.mutable.Map[String, String]() ++= requiredProperties
Config.readPropertiesFromEnvironment(required, env)
Config.readPropertiesFromSystemAndEnv(required, env)

// for optional value, assign them a default from the required properties list
// to prevent loss of a default value on a required property that may not otherwise be defined
val optional = scala.collection.mutable.Map[String, String]() ++= optionalProperties.map { k =>
k -> required.getOrElse(k, null)
}
Config.readPropertiesFromEnvironment(optional, env)
Config.readPropertiesFromSystemAndEnv(optional, env)

required ++ optional
}
Expand All @@ -133,13 +133,15 @@ class Config(requiredProperties: Map[String, String], optionalProperties: Set[St
* Singleton object which provides global methods to manage configuration.
*/
object Config {
val prefix = "whisk-config."

/**
* Reads a Map of key-value pairs from the environment -- store them in the
* mutable properties object.
*/
def readPropertiesFromEnvironment(properties: scala.collection.mutable.Map[String, String], env: Map[String, String])(
implicit logging: Logging) = {
def readPropertiesFromSystemAndEnv(properties: scala.collection.mutable.Map[String, String],
env: Map[String, String])(implicit logging: Logging) = {
readPropertiesFromSystem(properties)
for (p <- properties.keys) {
val envp = p.replace('.', '_').toUpperCase
val envv = env.get(envp)
Expand All @@ -150,6 +152,16 @@ object Config {
}
}

def readPropertiesFromSystem(properties: scala.collection.mutable.Map[String, String])(implicit logging: Logging) = {
for (p <- properties.keys) {
val sysv = Option(System.getProperty(prefix + p))
if (sysv.isDefined) {
logging.info(this, s"system set value for $p")
properties += p -> sysv.get.trim
}
}
}

/**
* Checks that the properties object defines all the required properties.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,12 @@ class AkkaLogging(loggingAdapter: LoggingAdapter) extends Logging {
val logmsg: String = message // generates the message
if (logmsg.nonEmpty) { // log it only if its not empty
val name = if (from.isInstanceOf[String]) from else Logging.getCleanSimpleClassName(from.getClass)
loggingAdapter.log(loglevel, s"[$id] [$name] $logmsg")
loggingAdapter.log(loglevel, format(id, name.toString, logmsg))
}
}
}

protected def format(id: TransactionId, name: String, logmsg: String) = s"[$id] [$name] $logmsg"
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,14 @@ class WhiskConfig(requiredProperties: Map[String, String],
*/
override protected def getProperties() = {
val properties = super.getProperties()
WhiskConfig.readPropertiesFromFile(properties, Option(propertiesFile) getOrElse (WhiskConfig.whiskPropertiesFile))
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)
Expand Down Expand Up @@ -85,6 +89,7 @@ class WhiskConfig(requiredProperties: Map[String, String],
}

object WhiskConfig {
val disableWhiskPropsFileRead = Config.prefix + "disable.whisks.props.file.read"

/**
* Reads a key from system environment as if it was part of WhiskConfig.
Expand Down Expand Up @@ -170,7 +175,7 @@ object WhiskConfig {
val kafkaHostList = "kafka.hosts"
val zookeeperHostList = "zookeeper.hosts"

private val edgeHostApiPort = "edge.host.apiport"
val edgeHostApiPort = "edge.host.apiport"

val invokerHostsList = "invoker.hosts"
val dbHostsList = "db.hostsList"
Expand Down Expand Up @@ -217,6 +222,7 @@ object ConfigKeys {
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"

Expand Down Expand Up @@ -255,4 +261,6 @@ object ConfigKeys {

val metrics = "whisk.metrics"
val featureFlags = "whisk.feature-flags"

val whiskConfig = "whisk.config"
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ trait Container {
protected var containerHttpMaxConcurrent: Int = 1
protected var containerHttpTimeout: FiniteDuration = 60.seconds

def containerId: ContainerId = id

/** Stops the container from consuming CPU cycles. NOT thread-safe - caller must synchronize. */
def suspend()(implicit transid: TransactionId): Future[Unit] = {
//close connection first, then close connection pool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import akka.stream.SinkShape
import akka.stream.scaladsl.{Broadcast, Flow, GraphDSL, Keep, Sink}
import akka.util.ByteString
import spray.json.DefaultJsonProtocol._
import spray.json.{JsObject, RootJsonFormat}
import spray.json.{JsObject, JsValue, RootJsonFormat}
import org.apache.openwhisk.common.{Logging, StartMarker, TransactionId}
import org.apache.openwhisk.core.entity.{DocInfo, DocRevision, DocumentReader, WhiskDocument}

Expand Down Expand Up @@ -97,6 +97,21 @@ private[database] object StoreUtils {
s"$encodedAlgoName-$digest"
}

/**
* Transforms a json object by adding and removing fields
*
* @param json base json object to transform
* @param fieldsToAdd list of fields to add. If the value provided is `None` then it would be ignored
* @param fieldsToRemove list of field names to remove
* @return transformed json
*/
def transform(json: JsObject,
fieldsToAdd: Seq[(String, Option[JsValue])],
fieldsToRemove: Seq[String] = Seq.empty): JsObject = {
val fields = json.fields ++ fieldsToAdd.flatMap(f => f._2.map((f._1, _))) -- fieldsToRemove
JsObject(fields)
}

private def combineResult[T](digest: Future[String], length: Future[Long], upload: Future[T])(
implicit ec: ExecutionContext) = {
for {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import com.microsoft.azure.cosmosdb.internal.Constants.Properties
import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient
import kamon.metric.MeasurementUnit
import org.apache.openwhisk.common.{LogMarkerToken, Logging, LoggingMarkers, MetricEmitter, Scheduler, TransactionId}
import org.apache.openwhisk.core.database.StoreUtils.{checkDocHasRevision, deserialize, reportFailure}
import org.apache.openwhisk.core.database.StoreUtils._
import org.apache.openwhisk.core.database._
import org.apache.openwhisk.core.database.cosmosdb.CosmosDBArtifactStoreProvider.DocumentClientRef
import org.apache.openwhisk.core.database.cosmosdb.CosmosDBConstants._
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ package org.apache.openwhisk.core.database.cosmosdb

import com.microsoft.azure.cosmosdb.internal.Constants.Properties.{AGGREGATE, E_TAG, ID, SELF_LINK}
import org.apache.openwhisk.core.database.cosmosdb.CosmosDBConstants._
import spray.json.{JsObject, JsString, JsValue}
import org.apache.openwhisk.core.database.StoreUtils.transform
import spray.json.{JsObject, JsString}

import scala.collection.immutable.Iterable

Expand Down Expand Up @@ -124,21 +125,6 @@ private[cosmosdb] trait CosmosDBUtil {
transform(stripInternalFields(js), fieldsToAdd, Seq.empty)
}

/**
* Transforms a json object by adding and removing fields
*
* @param json base json object to transform
* @param fieldsToAdd list of fields to add. If the value provided is `None` then it would be ignored
* @param fieldsToRemove list of field names to remove
* @return transformed json
*/
def transform(json: JsObject,
fieldsToAdd: Seq[(String, Option[JsValue])],
fieldsToRemove: Seq[String] = Seq.empty): JsObject = {
val fields = json.fields ++ fieldsToAdd.flatMap(f => f._2.map((f._1, _))) -- fieldsToRemove
JsObject(fields)
}

private def stripInternalFields(js: JsObject) = {
//Strip out all field name starting with '_' which are considered as db specific internal fields
JsObject(js.fields.filter { case (k, _) => !k.startsWith("_") && k != cid })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@

package org.apache.openwhisk.core.database.memory

import java.nio.charset.StandardCharsets.UTF_8

import akka.actor.ActorSystem
import akka.http.scaladsl.model.{ContentType, Uri}
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.{Sink, Source}
import akka.util.ByteString
import pureconfig.loadConfigOrThrow
import spray.json.{DefaultJsonProtocol, DeserializationException, JsObject, JsString, RootJsonFormat}
import org.apache.openwhisk.common.{Logging, LoggingMarkers, TransactionId}
import org.apache.openwhisk.core.ConfigKeys
import org.apache.openwhisk.core.database.StoreUtils._
Expand All @@ -32,13 +32,16 @@ import org.apache.openwhisk.core.entity.Attachments.Attached
import org.apache.openwhisk.core.entity._
import org.apache.openwhisk.core.entity.size._
import org.apache.openwhisk.http.Messages
import pureconfig.loadConfigOrThrow
import spray.json.{DefaultJsonProtocol, DeserializationException, JsObject, JsString, RootJsonFormat}

import scala.collection.concurrent.TrieMap
import scala.concurrent.{ExecutionContext, Future}
import scala.reflect.ClassTag
import scala.util.{Failure, Success, Try}

object MemoryArtifactStoreProvider extends ArtifactStoreProvider {
private val stores = new TrieMap[String, MemoryArtifactStore[_]]()
override def makeStore[D <: DocumentSerializer: ClassTag](useBatching: Boolean)(
implicit jsonFormat: RootJsonFormat[D],
docReader: DocumentReader,
Expand All @@ -58,9 +61,12 @@ object MemoryArtifactStoreProvider extends ArtifactStoreProvider {
val classTag = implicitly[ClassTag[D]]
val (dbName, handler, viewMapper) = handlerAndMapper(classTag)
val inliningConfig = loadConfigOrThrow[InliningConfig](ConfigKeys.db)
new MemoryArtifactStore(dbName, handler, viewMapper, inliningConfig, attachmentStore)
val storeFactory = () => new MemoryArtifactStore(dbName, handler, viewMapper, inliningConfig, attachmentStore)
stores.getOrElseUpdate(dbName, storeFactory.apply()).asInstanceOf[ArtifactStore[D]]
}

def purgeAll(): Unit = stores.clear()

private def handlerAndMapper[D](entityType: ClassTag[D])(
implicit actorSystem: ActorSystem,
logging: Logging,
Expand Down Expand Up @@ -96,6 +102,8 @@ class MemoryArtifactStore[DocumentAbstraction <: DocumentSerializer](dbName: Str
with DocumentProvider
with AttachmentSupport[DocumentAbstraction] {

logging.info(this, s"Created MemoryStore for [$dbName]")

override protected[core] implicit val executionContext: ExecutionContext = system.dispatcher

private val artifacts = new TrieMap[String, Artifact]
Expand All @@ -110,22 +118,25 @@ class MemoryArtifactStore[DocumentAbstraction <: DocumentSerializer](dbName: Str
val id = asJson.fields(_id).convertTo[String].trim
require(!id.isEmpty, "document id must be defined")

val rev: Int = getRevision(asJson)
val docinfoStr = s"id: $id, rev: $rev"
val (oldRev, newRev) = computeRevision(asJson)
val docinfoStr = s"id: $id, rev: ${oldRev.getOrElse("null")}"
val start = transid.started(this, LoggingMarkers.DATABASE_SAVE, s"[PUT] '$dbName' saving document: '$docinfoStr'")

val existing = Artifact(id, rev, asJson)
val updated = existing.incrementRev()
val updated = Artifact(id, newRev, asJson)
val t = Try[DocInfo] {
if (rev == 0) {
artifacts.putIfAbsent(id, updated) match {
case Some(_) => throw DocumentConflictException("conflict on 'put'")
case None => updated.docInfo
}
} else if (artifacts.replace(id, existing, updated)) {
updated.docInfo
} else {
throw DocumentConflictException("conflict on 'put'")
oldRev match {
case Some(rev) =>
val existing = Artifact(id, rev, asJson)
if (artifacts.replace(id, existing, updated)) {
updated.docInfo
} else {
throw DocumentConflictException("conflict on 'put'")
}
case None =>
artifacts.putIfAbsent(id, updated) match {
case Some(_) => throw DocumentConflictException("conflict on 'put'")
case None => updated.docInfo
}
}
}

Expand Down Expand Up @@ -285,7 +296,6 @@ class MemoryArtifactStore[DocumentAbstraction <: DocumentSerializer](dbName: Str
}

override def shutdown(): Unit = {
artifacts.clear()
attachmentStore.shutdown()
}

Expand All @@ -308,38 +318,34 @@ class MemoryArtifactStore[DocumentAbstraction <: DocumentSerializer](dbName: Str
reportFailure(f, start, failure => s"[GET] '$dbName' internal error, doc: '$id', failure: '${failure.getMessage}'")
}

private def getRevision(asJson: JsObject) = {
asJson.fields.get(_rev) match {
case Some(JsString(r)) => r.toInt
case _ => 0
private def computeRevision(js: JsObject): (Option[String], String) = {
js.fields.get(_rev) match {
case Some(JsString(r)) => (Some(r), digest(js))
case _ => (None, digest(js))
}
}

private def digest(js: JsObject) = {
val jsWithoutRev = transform(js, Seq.empty, Seq(_rev))
val md = emptyDigest()
encodeDigest(md.digest(jsWithoutRev.compactPrint.getBytes(UTF_8)))
}

//Use curried case class to allow equals support only for id and rev
//This allows us to implement atomic replace and remove which check
//for id,rev equality only
private case class Artifact(id: String, rev: Int)(val doc: JsObject, val computed: JsObject) {
def incrementRev(): Artifact = {
val (newRev, updatedDoc) = incrementAndGet()
copy(rev = newRev)(updatedDoc, computed) //With Couch attachments are lost post update
}

private case class Artifact(id: String, rev: String)(val doc: JsObject, val computed: JsObject) {
def docInfo = DocInfo(DocId(id), DocRevision(rev.toString))

private def incrementAndGet() = {
val newRev = rev + 1
val updatedDoc = JsObject(doc.fields + (_rev -> JsString(newRev.toString)))
(newRev, updatedDoc)
}
}

private object Artifact {
def apply(id: String, rev: Int, doc: JsObject): Artifact = {
Artifact(id, rev)(doc, documentHandler.computedFields(doc))
def apply(id: String, rev: String, doc: JsObject): Artifact = {
val docWithRev = transform(doc, Seq((_rev, Some(JsString(rev)))))
Artifact(id, rev)(docWithRev, documentHandler.computedFields(doc))
}

def apply(info: DocInfo): Artifact = {
Artifact(info.id.id, info.rev.rev.toInt)(JsObject.empty, JsObject.empty)
Artifact(info.id.id, info.rev.rev)(JsObject.empty, JsObject.empty)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,11 @@ object BasicHttpService {
/**
* Starts an HTTP(S) route handler on given port and registers a shutdown hook.
*/
def startHttpService(route: Route, port: Int, config: Option[HttpsConfig] = None)(
def startHttpService(route: Route, port: Int, config: Option[HttpsConfig] = None, interface: String = "0.0.0.0")(
implicit actorSystem: ActorSystem,
materializer: ActorMaterializer): Unit = {
val connectionContext = config.map(Https.connectionContext(_)).getOrElse(HttpConnectionContext)
val httpBinding = Http().bindAndHandle(route, "0.0.0.0", port, connectionContext = connectionContext)
val httpBinding = Http().bindAndHandle(route, interface, port, connectionContext = connectionContext)
addShutdownHook(httpBinding)
}

Expand Down
1 change: 1 addition & 0 deletions core/controller/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ whisk {
}
controller {
protocol: http
interface: "0.0.0.0"
}
}
Loading