Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7cf55bb
Build and copy route management actions to standalone jar
chetanmeh Jul 25, 2019
c3c8ae5
Install route management packages on startup
chetanmeh Jul 25, 2019
02bf297
Use ow logging api to log install command results
chetanmeh Jul 25, 2019
8dd456e
Delete action zip from local fs post install
chetanmeh Jul 25, 2019
fe08b66
Add pre flight check for configured server ports to be free
chetanmeh Jul 25, 2019
c1edbd8
Support launching Redis
chetanmeh Jul 25, 2019
225f542
Launch Api Gateway
chetanmeh Jul 26, 2019
a69121c
Fix the url and port used for apigw
chetanmeh Jul 26, 2019
d74b527
Change the config path to standalone namespace
chetanmeh Jul 26, 2019
3fd8f5c
Pass the local host ip to api gateway
chetanmeh Jul 26, 2019
c2903f4
Support fetching proper ip on linux
chetanmeh Jul 26, 2019
047de23
Improve support for linux to pass hostIp for callback
chetanmeh Jul 26, 2019
c7f55f2
Fix docker command
chetanmeh Jul 26, 2019
f2e4e39
Refactor logic related to handle localhost access
chetanmeh Jul 29, 2019
046cf5a
Fix command for Mac
chetanmeh Jul 29, 2019
023ffd1
Fix localhost address
chetanmeh Jul 29, 2019
d33f0a5
Do away with direct usage of host.docker.internal and instead use the…
chetanmeh Jul 29, 2019
3d09fe7
Use the hostIp for managed url on linux
chetanmeh Jul 29, 2019
b3f2c4c
Use localHostName method instead of literal localhost
chetanmeh Jul 29, 2019
3da2410
Fix server startup check to log the server name
chetanmeh Jul 29, 2019
2ab4927
Make test bound server on all ip
chetanmeh Jul 29, 2019
b6a67cc
Disable short flag `-a` for api gateway
chetanmeh Jul 29, 2019
20c555b
Add docs related to api gateway
chetanmeh Jul 29, 2019
6c3be74
Trim space
chetanmeh Jul 29, 2019
b7e4541
Reorder startup sequence
chetanmeh Jul 30, 2019
53013b7
Log details related to launched services
chetanmeh Jul 30, 2019
a34af6c
Change prefix for launched containers
chetanmeh Jul 30, 2019
62123ed
Avoid determining ip for non api gw mode as it fails on older Docker …
chetanmeh Jul 30, 2019
0041b77
Add check for minimal supported docker version
chetanmeh Jul 30, 2019
0c0af36
Add test for Api Gw
chetanmeh Jul 30, 2019
85b0f6e
Run tests within standalone project
chetanmeh Jul 30, 2019
6a63a3d
Allow configuring wsk path
chetanmeh Jul 30, 2019
2a61851
Download cli for unit test case as its needed by Standalone tests
chetanmeh Jul 30, 2019
02dbc39
Download cli
chetanmeh Jul 30, 2019
d8f2aed
Avoid zipping common js files twice for setups where installRouteMgmt…
chetanmeh Jul 31, 2019
fccc59a
Run standalone integration tests in system profile as it needs wsk cli
chetanmeh Jul 31, 2019
5df5e1f
Run tests from correct directory
chetanmeh Jul 31, 2019
ca4a346
Wait for route management actions to be installed prior to starting t…
chetanmeh Jul 31, 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
16 changes: 14 additions & 2 deletions core/standalone/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,11 @@ $ java -jar openwhisk-standalone.jar -h
\ \ / \/ \___/| .__/ \___|_| |_|__/\__|_| |_|_|___/_|\_\
\___\/ tm |_|

--api-gw Enable API Gateway support
--api-gw-port <arg> Api Gateway Port
-c, --config-file <arg> application.conf which overrides the default
standalone.conf
-d, --data-dir <arg> Directory used for storage
--disable-color-logging Disables colored logging
-m, --manifest <arg> Manifest json defining the supported runtimes
-p, --port <arg> Server port
Expand All @@ -85,6 +88,7 @@ $ java -jar openwhisk-standalone.jar -h
--version Show version of this program

OpenWhisk standalone server

```

Sections below would illustrate some of the supported options
Expand Down Expand Up @@ -189,5 +193,13 @@ whisk {

Then pass this config file via `-c` option.

[1]: https://github.com/apache/openwhisk/blob/master/docs/cli.md
[2]: https://github.com/apache/openwhisk/blob/master/docs/samples.md
#### Using Api Gateway

Api Gateway mode can be enabled via `--api-gw` flag. In this mode upon launch a separate container for [OpenWhisk Api gateway][3]
would be launched on port `3234` (can be changed with `--api-gw-port`). In this mode you can make use of the
[api gateway][4] support.

[1]: https://github.com/apache/incubator-openwhisk/blob/master/docs/cli.md
[2]: https://github.com/apache/incubator-openwhisk/blob/master/docs/samples.md
[3]: https://github.com/apache/incubator-openwhisk-apigateway
[4]: https://github.com/apache/incubator-openwhisk/blob/master/docs/apigateway.md
52 changes: 52 additions & 0 deletions core/standalone/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,42 @@ task copySwagger(type: Copy) {
project.ext.swaggerUiDir = file("$buildDir/tmp/swagger/swagger-ui/swagger-ui-${version}/dist")
}

def apiGwActions = ['createApi', "deleteApi", "getApi"]

task copyGWActions() {
doLast {
def routeMgmtDir = new File(project.projectDir.getParentFile(), "routemgmt")
def commonDir = new File(routeMgmtDir, "common")
def routeBuildDir = mkdir("$buildDir/tmp/routemgmt")
apiGwActions.each { actionName ->
def zipFileName = actionName + ".zip"
def actionDir = new File(routeMgmtDir, actionName)
def zipFile = new File(routeBuildDir, zipFileName)
if (!zipFile.exists()) {
ant.exec(dir:actionDir, executable:"npm", failonerror:true){
arg(line:"install")
}
ant.zip(destfile:zipFile){
fileset(dir:actionDir){
exclude(name:zipFileName)
//Somehow if in zip we add same file twice it causes issues
//Its possible that installRouteMgmt.sh has been invoked which would
//have copied the common files to each action dir.
//Exclude such files to zipped twice
commonDir.listFiles().each {f ->
exclude(name:f.name)
}
}
fileset(dir:commonDir)
}
logger.info("Create action zip $zipFileName")
}
}
}
}

processResources.dependsOn copySwagger
processResources.dependsOn copyGWActions

processResources {
from(new File(project.rootProject.projectDir, "ansible/files/runtimes.json")) {
Expand All @@ -64,6 +99,11 @@ processResources {
exclude "index.html"
into("swagger-ui")
}
apiGwActions.each { action ->
from(file("$buildDir/tmp/routemgmt/${action}.zip")){
into(".")
}
}
}

task copyBootJarToBin(type:Copy){
Expand All @@ -86,5 +126,17 @@ dependencies {
compile project(':core:controller')
compile project(':tools:admin')
compile 'org.rogach:scallop_2.12:3.3.1'

testCompile 'junit:junit:4.11'
testCompile 'org.scalatest:scalatest_2.12:3.0.5'
}

gradle.projectsEvaluated {
tasks.withType(Test) {
testLogging {
events "passed", "skipped", "failed"
showStandardStreams = true
exceptionFormat = 'full'
}
}
}
10 changes: 10 additions & 0 deletions core/standalone/src/main/resources/standalone.conf
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,14 @@ whisk {
file-system : false
dir-path : "BOOT-INF/classes/swagger-ui"
}

standalone {
redis {
image: "redis:4.0"
}

api-gateway {
image: "openwhisk/apigateway:nightly"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* 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.standalone

import akka.actor.{ActorSystem, Scheduler}
import akka.http.scaladsl.model.Uri
import akka.pattern.RetrySupport
import org.apache.openwhisk.common.{Logging, TransactionId}
import org.apache.openwhisk.core.containerpool.docker.BrokenDockerContainer
import org.apache.openwhisk.standalone.StandaloneDockerSupport.{containerName, createRunCmd}
import pureconfig.loadConfigOrThrow

import scala.concurrent.duration._
import scala.concurrent.{ExecutionContext, Future}

class ApiGwLauncher(docker: StandaloneDockerClient, apiGwApiPort: Int, apiGwMgmtPort: Int, serverPort: Int)(
implicit logging: Logging,
ec: ExecutionContext,
actorSystem: ActorSystem,
tid: TransactionId)
extends RetrySupport {
private implicit val scd: Scheduler = actorSystem.scheduler
case class RedisConfig(image: String)
case class ApiGwConfig(image: String)
private val redisConfig = loadConfigOrThrow[RedisConfig](StandaloneConfigKeys.redisConfigKey)
private val apiGwConfig = loadConfigOrThrow[ApiGwConfig](StandaloneConfigKeys.apiGwConfigKey)

def run(): Future[Seq[ServiceContainer]] = {
for {
(redis, redisSvcs) <- runRedis()
_ <- waitForRedis(redis)
(_, apiGwSvcs) <- runApiGateway(redis)
_ <- waitForApiGw()
} yield Seq(redisSvcs, apiGwSvcs).flatten
}

def runRedis(): Future[(StandaloneDockerContainer, Seq[ServiceContainer])] = {
val defaultRedisPort = 6379
val redisPort = StandaloneDockerSupport.checkOrAllocatePort(defaultRedisPort)
logging.info(this, s"Starting Redis at $redisPort")

val params = Map("-p" -> Set(s"$redisPort:6379"))
val name = containerName("redis")
val args = createRunCmd(name, dockerRunParameters = params)
val f = runDetached(redisConfig.image, args, pull = true)
val sc = ServiceContainer(redisPort, "Redis", name)
f.map(c => (c, Seq(sc)))
}

def waitForRedis(c: StandaloneDockerContainer): Future[Unit] = {
retry(() => isRedisUp(c), 12, 5.seconds)
}

private def isRedisUp(c: StandaloneDockerContainer) = {
val args = Seq(
"run",
"--rm",
"--name",
containerName("redis-test"),
redisConfig.image,
"redis-cli",
"-h",
c.addr.host,
"-p",
"6379",
"ping")
docker.runCmd(args, docker.clientConfig.timeouts.run).map(out => require(out.toLowerCase == "pong"))
}

def runApiGateway(redis: StandaloneDockerContainer): Future[(StandaloneDockerContainer, Seq[ServiceContainer])] = {
val hostIp = StandaloneDockerSupport.getLocalHostIp()
val env = Map(
"BACKEND_HOST" -> s"http://$hostIp:$serverPort",
"REDIS_HOST" -> redis.addr.host,
"REDIS_PORT" -> "6379",
//This is the name used to render the final url. So should be localhost
//as that would be used by end user outside of docker
"PUBLIC_MANAGEDURL_HOST" -> StandaloneDockerSupport.getLocalHostName(),
"PUBLIC_MANAGEDURL_PORT" -> apiGwMgmtPort.toString)

logging.info(this, s"Starting Api Gateway at api port: $apiGwApiPort, management port: $apiGwMgmtPort")
val name = containerName("apigw")
val params = Map("-p" -> Set(s"$apiGwApiPort:9000", s"$apiGwMgmtPort:8080"))
val args = createRunCmd(name, env, params)

//TODO ExecManifest is scoped to core. Ideally we would like to do
// ExecManifest.ImageName(apiGwConfig.image).prefix.contains("openwhisk")
val pull = apiGwConfig.image.startsWith("openwhisk")
val f = runDetached(apiGwConfig.image, args, pull)
val sc = Seq(
ServiceContainer(apiGwApiPort, "Api Gateway - Api Service", name),
ServiceContainer(apiGwMgmtPort, "Api Gateway - Management Service", name))
f.map(c => (c, sc))
}

def waitForApiGw(): Future[Unit] = {
new ServerStartupCheck(
Uri(s"http://${StandaloneDockerSupport.getLocalHostName()}:$apiGwApiPort/v1/apis"),
"ApiGateway")
.waitForServerToStart()
Future.successful(())
}

private def runDetached(image: String, args: Seq[String], pull: Boolean): Future[StandaloneDockerContainer] = {
for {
_ <- if (pull) docker.pull(image) else Future.successful(())
id <- docker.run(image, args).recoverWith {
case t @ BrokenDockerContainer(brokenId, _) =>
// Remove the broken container - but don't wait or check for the result.
// If the removal fails, there is nothing we could do to recover from the recovery.
docker.rm(brokenId)
Future.failed(t)
case t => Future.failed(t)
}
ip <- docker.inspectIPAddress(id, StandaloneDockerSupport.network).recoverWith {
// remove the container immediately if inspect failed as
// we cannot recover that case automatically
case e =>
docker.rm(id)
Future.failed(e)
}
} yield StandaloneDockerContainer(id, ip)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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.standalone

import scala.util.control.NonFatal

case class DockerVersion(major: Int, minor: Int, patch: Int) extends Ordered[DockerVersion] {
import scala.math.Ordered.orderingToOrdered
def compare(that: DockerVersion): Int =
(this.major, this.minor, this.patch) compare (that.major, that.minor, that.patch)

override def toString = s"$major.$minor.$patch"
}

object DockerVersion {
implicit val ord: Ordering[DockerVersion] = Ordering.by(unapply)
private val pattern = ".*Docker version ([\\d.]+).*".r

def apply(str: String): DockerVersion = {
try {
val parts = if (str != null && str.nonEmpty) str.split('.') else Array[String]()
val major = if (parts.length >= 1) parts(0).toInt else 0
val minor = if (parts.length >= 2) parts(1).toInt else 0
val patch = if (parts.length >= 3) parts(2).toInt else 0
DockerVersion(major, minor, patch)
} catch {
case NonFatal(_) => throw new IllegalArgumentException(s"bad docker version $str")
}
}

def fromVersionCommand(str: String): DockerVersion = {
val pattern(version) = str
apply(version)
}
}
Loading