Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 0 additions & 1 deletion library/java/src/io/envoyproxy/envoymobile/engine/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ envoy_mobile_java_library(
name = "envoy_base_engine_lib",
srcs = [
"EnvoyConfiguration.java",
"EnvoyConfigurationImpl.java",
"EnvoyEngine.java",
"EnvoyEngineImpl.java",
"EnvoyHTTPStream.java",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,46 @@
package io.envoyproxy.envoymobile.engine;

public interface EnvoyConfiguration {
public class EnvoyConfiguration {

public final Integer connectTimeoutSeconds;
public final Integer dnsRefreshSeconds;
public final Integer statsFlushSeconds;

/**
* Provides a default configuration template that may be used for starting Envoy.
* Create an EnvoyConfiguration with a user provided configuration values.
*
* @return A template that may be used as a starting point for constructing configurations.
* @param connectTimeoutSeconds timeout for new network connections to hosts in the cluster.
* @param dnsRefreshSeconds rate in seconds to refresh DNS.
* @param statsFlushSeconds interval at which to flush Envoy stats.
*/
String templateString();
public EnvoyConfiguration(int connectTimeoutSeconds, int dnsRefreshSeconds,
int statsFlushSeconds) {
this.connectTimeoutSeconds = connectTimeoutSeconds;
this.dnsRefreshSeconds = dnsRefreshSeconds;
this.statsFlushSeconds = statsFlushSeconds;
}

/**
* Resolves the provided configuration template using properties on this configuration.
* This default configuration is provided by the native layer.
*
* @param templateYAML the default template configuration.
* @return String, the resolved template.
* @throws ConfigurationException, when the template provided is not fully resolved.
*/
String resolveTemplate(String templateYAML) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on moving the logic in this function into EnvoyConfigurationImpl (could be a helper method called out of runWithConfig)? That way the configuration really doesn't need to know or care about any implementation details of how its attributes are used.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can create another file which holds this method and just port the unit tests there -- it'll make this class a pure data class then. Wdyt?

cc: @rebello95

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I'm good with that

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, let's revisit at a later date on this 😬

String resolvedConfiguration =
templateYAML.replace("{{ connect_timeout }}", String.format("%ss", connectTimeoutSeconds))
.replace("{{ dns_refresh_rate }}", String.format("%ss", dnsRefreshSeconds))
.replace("{{ stats_flush_interval }}", String.format("%ss", statsFlushSeconds));

if (resolvedConfiguration.contains("{{")) {
throw new ConfigurationException();
}
return resolvedConfiguration;
}

static class ConfigurationException extends RuntimeException {
ConfigurationException() { super("Unresolved Template Key"); }
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ public interface EnvoyEngine {
EnvoyHTTPStream startStream(EnvoyObserver observer);

/**
* Run the Envoy engine with the provided config and log level.
* Run the Envoy engine with the provided yaml string and log level.
*
* @param config The configuration file with which to start Envoy.
* @param configurationYAML The configuration yaml with which to start Envoy.
* @return A status indicating if the action was successful.
*/
int runWithConfig(String config);
int runWithConfig(String configurationYAML, String logLevel);

/**
* Run the Envoy engine with the provided config and log level.
* Run the Envoy engine with the provided EnvoyConfiguration and log level.
*
* @param config The configuration file with which to start Envoy.
* @param envoyConfiguration The EnvoyConfiguration used to start Envoy.
* @param logLevel The log level to use when starting Envoy.
* @return int A status indicating if the action was successful.
*/
int runWithConfig(String config, String logLevel);
int runWithConfig(EnvoyConfiguration envoyConfiguration, String logLevel);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,30 @@ public EnvoyHTTPStream startStream(EnvoyObserver observer) {
}

/**
* Run the Envoy engine with the provided config and log level.
* Run the Envoy engine with the provided yaml string and log level.
*
* @param config The configuration file with which to start Envoy.
* @param configurationYAML The configuration yaml with which to start Envoy.
* @return A status indicating if the action was successful.
*/
@Override
public int runWithConfig(String config) {
return runWithConfig(config, "info");
public int runWithConfig(String configurationYAML, String logLevel) {
try {
return JniLibrary.runEngine(configurationYAML, logLevel);
} catch (Throwable throwable) {
// TODO: Need to have a way to log the exception somewhere
return 1;
}
}

/**
* Run the Envoy engine with the provided config and log level.
* Run the Envoy engine with the provided envoyConfiguration and log level.
*
* @param config The configuration file with which to start Envoy.
* @param envoyConfiguration The EnvoyConfiguration used to start Envoy.
* @param logLevel The log level to use when starting Envoy.
* @return int A status indicating if the action was successful.
*/
@Override
public int runWithConfig(String config, String logLevel) {
try {
return JniLibrary.runEngine(config, logLevel);
} catch (Throwable throwable) {
// TODO: Need to have a way to log the exception somewhere
return 1;
}
public int runWithConfig(EnvoyConfiguration envoyConfiguration, String logLevel) {
return runWithConfig(envoyConfiguration.resolveTemplate(JniLibrary.templateString()), logLevel);
}
}
13 changes: 13 additions & 0 deletions library/java/test/io/envoyproxy/envoymobile/engine/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
licenses(["notice"]) # Apache 2

load("//bazel:kotlin_test.bzl", "envoy_mobile_kt_test")

envoy_mobile_kt_test(
name = "envoy_configuration_test",
srcs = [
"EnvoyConfigurationTest.kt",
],
deps = [
"//library/kotlin/src/io/envoyproxy/envoymobile:envoy_interfaces_lib",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.envoyproxy.envoymobile.engine

import org.junit.Test

private const val TEST_CONFIG = """
mock_template:
- name: mock
connect_timeout: {{ connect_timeout }}
dns_refresh_rate: {{ dns_refresh_rate }}
stats_flush_interval: {{ stats_flush_interval }}
"""


class EnvoyConfigurationTest {

@Test
fun `resolving with default configuration resolves with values`() {
val envoyConfiguration = EnvoyConfiguration(123, 234, 345)

val resolvedTemplate = envoyConfiguration.resolveTemplate(TEST_CONFIG)
assertThat(resolvedTemplate).contains("connect_timeout: 123s")
assertThat(resolvedTemplate).contains("dns_refresh_rate: 234s")
assertThat(resolvedTemplate).contains("stats_flush_interval: 345s")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe also assert that the template doesn't contain any {{?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The behavior that is baked in the method is that if it contains any unresolved templates, we'll throw an exception so that test is: resolve templates with invalid templates will throw on build

}


@Test(expected = ConfigurationException::class)
fun `resolve templates with invalid templates will throw on build`() {
val envoyConfiguration = EnvoyConfiguration(123, 234, 345)

envoyConfiguration.resolveTemplate("{{ }}")
}
}
17 changes: 12 additions & 5 deletions library/kotlin/src/io/envoyproxy/envoymobile/Envoy.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.envoyproxy.envoymobile

import io.envoyproxy.envoymobile.engine.EnvoyConfiguration
import io.envoyproxy.envoymobile.engine.EnvoyEngine
import java.nio.ByteBuffer

Expand All @@ -19,17 +20,23 @@ enum class LogLevel(internal val level: String) {
/**
* Wrapper class that allows for easy calling of Envoy's JNI interface in native Java.
*/
class Envoy constructor(
class Envoy private constructor(
private val engine: EnvoyEngine,
internal val config: String,
internal val logLevel: LogLevel = LogLevel.INFO
internal val envoyConfiguration: EnvoyConfiguration?,
internal val configurationYAML: String?,
internal val logLevel: LogLevel
) : Client {

constructor(engine: EnvoyEngine, config: String) : this(engine, config, LogLevel.INFO)
constructor(engine: EnvoyEngine, envoyConfiguration: EnvoyConfiguration, logLevel: LogLevel = LogLevel.INFO) : this(engine, envoyConfiguration, null, logLevel)
constructor(engine: EnvoyEngine, configurationYAML: String, logLevel: LogLevel = LogLevel.INFO) : this(engine, null, configurationYAML, logLevel)

// Dedicated thread for running this instance of Envoy.
private val runner: Thread = Thread(ThreadGroup("Envoy"), Runnable {
engine.runWithConfig(config.trim(), logLevel.level)
if (envoyConfiguration == null) {
engine.runWithConfig(configurationYAML, logLevel.level)
}else {
engine.runWithConfig(envoyConfiguration, logLevel.level)
}
})

/**
Expand Down
40 changes: 8 additions & 32 deletions library/kotlin/src/io/envoyproxy/envoymobile/EnvoyBuilder.kt
Original file line number Diff line number Diff line change
@@ -1,29 +1,20 @@
package io.envoyproxy.envoymobile

import io.envoyproxy.envoymobile.engine.EnvoyConfiguration
import io.envoyproxy.envoymobile.engine.EnvoyConfigurationImpl
import io.envoyproxy.envoymobile.engine.EnvoyEngine
import io.envoyproxy.envoymobile.engine.EnvoyEngineImpl

class ConfigurationException : Exception("Unresolved Template Key")

open class EnvoyBuilder internal constructor(
private val envoyConfiguration: EnvoyConfiguration
) {
private var logLevel = LogLevel.INFO
private var configYAML: String
private var configYAML: String? = null
private var engineType: () -> EnvoyEngine = { EnvoyEngineImpl() }

private var connectTimeoutSeconds = 30
private var dnsRefreshSeconds = 60
private var statsFlushSeconds = 60

constructor() : this(EnvoyConfigurationImpl())

init {
configYAML = envoyConfiguration.templateString()
}

/**
* Add a log level to use with Envoy.
* @param logLevel the log level to use with Envoy.
Expand All @@ -40,7 +31,7 @@ open class EnvoyBuilder internal constructor(
* @param configYAML the YAML file to use as a configuration.
*/
fun addConfigYAML(configYAML: String?): EnvoyBuilder {
this.configYAML = configYAML ?: envoyConfiguration.templateString()
this.configYAML = configYAML
return this
}

Expand Down Expand Up @@ -80,7 +71,12 @@ open class EnvoyBuilder internal constructor(
* @return A new instance of Envoy.
*/
fun build(): Envoy {
return Envoy(engineType(), resolvedYAML(), logLevel)
val configurationYAML = configYAML
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this really provides any benefit 🤷‍♂

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a variable and the class isn't thread safe so the field could be changed between the lines of code. This way at the start of the method call we are guaranteed to have the correct configuration yaml...

Basically, I get it's silly but the IDE was complaining to me so I changed it :(

if (configurationYAML == null) {
return Envoy(engineType(), EnvoyConfiguration(connectTimeoutSeconds, dnsRefreshSeconds, statsFlushSeconds), logLevel)
} else {
return Envoy(engineType(), configurationYAML, logLevel)
}
}

/**
Expand All @@ -92,24 +88,4 @@ open class EnvoyBuilder internal constructor(
this.engineType = engineType
return this
}


/** Processes the YAML template provided, replacing keys with values from the configuration.
*
* @parameter template: The template YAML file to use.
* @returns: A resolved YAML file with all template keys replaced.
* @throws ConfigurationException when the yaml configuration replacement is incomplete
*/
private fun resolvedYAML(): String {
val resolvedTemplate = configYAML
.replace("{{ connect_timeout }}", "${connectTimeoutSeconds}s")
.replace("{{ dns_refresh_rate }}", "${dnsRefreshSeconds}s")
.replace("{{ stats_flush_interval }}", "${statsFlushSeconds}s")

if (resolvedTemplate.contains("{{")) {
throw ConfigurationException()
}

return resolvedTemplate
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class ResponseHandler(val executor: Executor) {
override fun getExecutor(): Executor = responseHandler.executor

override fun onHeaders(headers: Map<String, List<String>>, endStream: Boolean) {
val statusCode = headers!![":status"]?.first()?.toIntOrNull() ?: 0
val statusCode = headers[":status"]?.first()?.toIntOrNull() ?: 0
responseHandler.onHeadersClosure(headers, statusCode, endStream)
}

Expand Down
Loading